diff options
Diffstat (limited to 'src/modules/rlm_eap')
85 files changed, 45825 insertions, 0 deletions
diff --git a/src/modules/rlm_eap/.gitignore b/src/modules/rlm_eap/.gitignore new file mode 100644 index 0000000..e713fa7 --- /dev/null +++ b/src/modules/rlm_eap/.gitignore @@ -0,0 +1 @@ +radeapclient diff --git a/src/modules/rlm_eap/all.mk b/src/modules/rlm_eap/all.mk new file mode 100644 index 0000000..f2cb44b --- /dev/null +++ b/src/modules/rlm_eap/all.mk @@ -0,0 +1 @@ +SUBMAKEFILES := libeap/all.mk rlm_eap.mk types/all.mk radeapclient.mk diff --git a/src/modules/rlm_eap/configure b/src/modules/rlm_eap/configure new file mode 100755 index 0000000..82428a9 --- /dev/null +++ b/src/modules/rlm_eap/configure @@ -0,0 +1,3512 @@ +#! /bin/sh +# From configure.ac Revision. +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="rlm_eap.c" +enable_option_checking=no +ac_subst_vars='LTLIBOBJS +LIBOBJS +targetname +mod_cflags +mod_ldflags +eaptypes +subdirs +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +runstatedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_rlm_eap +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS' +ac_subdirs_all='$eapsubdirs' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir runstatedir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --without-rlm_eap build without rlm_eap + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + +# Check whether --with-rlm_eap was given. +if test "${with_rlm_eap+set}" = set; then : + withval=$with_rlm_eap; +fi + + + +fail= +SMART_LIBS= +SMART_CLFAGS= + +if test x$with_rlm_eap != xno; then + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + eapsubdirs= + for foo in `find ./types -name configure -print`; do + bar=`echo $foo | sed 's%/configure$%%g'` + eapsubdirs="$eapsubdirs $bar" + done + + ln -s ../../../install-sh install-sh + + ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + + + +subdirs="$subdirs $eapsubdirs" + + rm install-sh + + + targetname=rlm_eap +else + targetname= + echo \*\*\* module rlm_eap is disabled. +fi + +if test x"$fail" != x""; then + if test x"${enable_strict_dependencies}" = x"yes"; then + as_fn_error $? "set --without-rlm_eap to disable it explicitly." "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_eap." >&5 +$as_echo "$as_me: WARNING: silently not building rlm_eap." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_eap requires: $fail." >&5 +$as_echo "$as_me: WARNING: FAILURE: rlm_eap requires: $fail." >&2;} + if test x"$headersuggestion" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $headersuggestion" >&5 +$as_echo "$as_me: WARNING: $headersuggestion" >&2;} + fi + if test x"$libsuggestion" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $libsuggestion" >&5 +$as_echo "$as_me: WARNING: $libsuggestion" >&2;} + fi + targetname="" + eapsubdirs="" + fi +fi + +eaptypes=types +if test x"$eapsubdirs" = x""; then + eaptypes="" +fi + +mod_ldflags="$SMART_LIBS" +mod_cflags="$SMART_CPPFLAGS" + + + + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi + +# +# CONFIG_SUBDIRS section. +# +if test "$no_recursion" != yes; then + + # Remove --cache-file, --srcdir, and --disable-option-checking arguments + # so they do not pile up. + ac_sub_configure_args= + ac_prev= + eval "set x $ac_configure_args" + shift + for ac_arg + do + if test -n "$ac_prev"; then + ac_prev= + continue + fi + case $ac_arg in + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ + | --c=*) + ;; + --config-cache | -C) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + ;; + --disable-option-checking) + ;; + *) + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_sub_configure_args " '$ac_arg'" ;; + esac + done + + # Always prepend --prefix to ensure using the same prefix + # in subdir configurations. + ac_arg="--prefix=$prefix" + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" + + # Pass --silent + if test "$silent" = yes; then + ac_sub_configure_args="--silent $ac_sub_configure_args" + fi + + # Always prepend --disable-option-checking to silence warnings, since + # different subdirs can have different --enable and --with options. + ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" + + ac_popdir=`pwd` + for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue + + # Do not complain, so a configure script can configure whichever + # parts of a large source tree are present. + test -d "$srcdir/$ac_dir" || continue + + ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" + $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 + $as_echo "$ac_msg" >&6 + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + cd "$ac_dir" + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f "$ac_srcdir/configure.gnu"; then + ac_sub_configure=$ac_srcdir/configure.gnu + elif test -f "$ac_srcdir/configure"; then + ac_sub_configure=$ac_srcdir/configure + elif test -f "$ac_srcdir/configure.in"; then + # This should be Cygnus configure. + ac_sub_configure=$ac_aux_dir/configure + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5 +$as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} + ac_sub_configure= + fi + + # The recursion is here. + if test -n "$ac_sub_configure"; then + # Make the cache file name correct relative to the subdirectory. + case $cache_file in + [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; + *) # Relative name. + ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 +$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} + # The eval makes quoting arguments work. + eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ + --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || + as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 + fi + + cd "$ac_popdir" + done +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/src/modules/rlm_eap/configure.ac b/src/modules/rlm_eap/configure.ac new file mode 100644 index 0000000..b1c0cfb --- /dev/null +++ b/src/modules/rlm_eap/configure.ac @@ -0,0 +1,69 @@ +AC_PREREQ([2.68]) +AC_INIT(rlm_eap.c) +AC_REVISION($Revision$) +FR_INIT_MODULE([rlm_eap]) + +fail= +SMART_LIBS= +SMART_CLFAGS= + +if test x$with_[]modname != xno; then + + AC_PROG_CC + + eapsubdirs= + for foo in `find ./types -name configure -print`; do + bar=`echo $foo | sed 's%/configure$%%g'` + eapsubdirs="$eapsubdirs $bar" + done + + dnl # don't ask... this is done to avoid autoconf stupidities. + ln -s ../../../install-sh install-sh + + dnl # + dnl # Don't change the variable name here. Autoconf goes bonkers + dnl # if you do. + dnl # + AC_CONFIG_SUBDIRS($eapsubdirs) + rm install-sh + + dnl # + dnl # Don't bother looking for errors in the child directories + dnl # + + targetname=modname +else + targetname= + echo \*\*\* module modname is disabled. +fi + +if test x"$fail" != x""; then + if test x"${enable_strict_dependencies}" = x"yes"; then + AC_MSG_ERROR([set --without-]modname[ to disable it explicitly.]) + else + AC_MSG_WARN([silently not building ]modname[.]) + AC_MSG_WARN([FAILURE: ]modname[ requires: $fail.]) + if test x"$headersuggestion" != x; then + AC_MSG_WARN([$headersuggestion]) + fi + if test x"$libsuggestion" != x; then + AC_MSG_WARN([$libsuggestion]) + fi + targetname="" + eapsubdirs="" + fi +fi + +eaptypes=types +if test x"$eapsubdirs" = x""; then + eaptypes="" +fi + +mod_ldflags="$SMART_LIBS" +mod_cflags="$SMART_CPPFLAGS" + +AC_SUBST(eaptypes) +AC_SUBST(mod_ldflags) +AC_SUBST(mod_cflags) +AC_SUBST(targetname) +AC_OUTPUT() diff --git a/src/modules/rlm_eap/eap.c b/src/modules/rlm_eap/eap.c new file mode 100644 index 0000000..f0452b4 --- /dev/null +++ b/src/modules/rlm_eap/eap.c @@ -0,0 +1,1270 @@ +/* + * eap.c rfc2284 & rfc2869 implementation + * + * 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 2000-2003,2006 The FreeRADIUS server project + * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com> + * Copyright 2003 Alan DeKok <aland@freeradius.org> + */ +/* + * EAP PACKET FORMAT + * --- ------ ------ + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Code | Identifier | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Data ... + * +-+-+-+-+ + * + * + * EAP Request and Response Packet Format + * --- ------- --- -------- ------ ------ + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Code | Identifier | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Type-Data ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- + * + * + * EAP Success and Failure Packet Format + * --- ------- --- ------- ------ ------ + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Code | Identifier | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +#include <freeradius-devel/modpriv.h> + +RCSID("$Id$") + +#include "rlm_eap.h" +#include <ctype.h> + +static char const *eap_codes[] = { + "", /* 0 is invalid */ + "Request", + "Response", + "Success", + "Failure" +}; + +static int _eap_module_free(eap_module_t *inst) +{ + /* + * We have to check inst->type as it's only allocated + * if we loaded the eap method. + */ + if (inst->type && inst->type->detach) (inst->type->detach)(inst->instance); + +#ifndef NDEBUG + /* + * Don't dlclose() modules if we're doing memory + * debugging. This removes the symbols needed by + * valgrind. + */ + if (!main_config.debug_memory) +#endif + if (inst->handle) dlclose(inst->handle); + + return 0; +} + +/** Load required EAP sub-modules (methods) + * + */ +int eap_module_instantiate(rlm_eap_t *inst, eap_module_t **m_inst, eap_type_t num, CONF_SECTION *cs) +{ + eap_module_t *method; + char *mod_name, *p; + + /* Make room for the EAP-Type */ + *m_inst = method = talloc_zero(cs, eap_module_t); + if (!inst) return -1; + + talloc_set_destructor(method, _eap_module_free); + + /* fill in the structure */ + method->cs = cs; + method->name = eap_type2name(num); + + /* + * The name of the module were trying to load + */ + mod_name = talloc_typed_asprintf(method, "rlm_eap_%s", method->name); + + /* + * dlopen is case sensitive + */ + p = mod_name; + while (*p) { + *p = tolower(*p); + p++; + } + + /* + * Link the loaded EAP-Type + */ + method->handle = fr_dlopenext(mod_name); + if (!method->handle) { + ERROR("rlm_eap (%s): Failed to link %s: %s", inst->xlat_name, mod_name, fr_strerror()); + + return -1; + } + + method->type = dlsym(method->handle, mod_name); + if (!method->type) { + ERROR("rlm_eap (%s): Failed linking to structure in %s: %s", inst->xlat_name, + method->name, dlerror()); + + return -1; + } + + cf_log_module(cs, "Linked to sub-module %s", mod_name); + + /* + * Call the attach num in the EAP num module + */ + if ((method->type->instantiate) && ((method->type->instantiate)(method->cs, &(method->instance)) < 0)) { + ERROR("rlm_eap (%s): Failed to initialise %s", inst->xlat_name, mod_name); + + if (method->instance) { + (void) talloc_steal(method, method->instance); + } + + return -1; + } + + if (method->instance) { + (void) talloc_steal(method, method->instance); + } + + return 0; +} + +/* + * Call the appropriate handle with the right eap_method. + */ +static int eap_module_call(eap_module_t *module, eap_handler_t *handler) +{ + int rcode = 1; + REQUEST *request = handler->request; + + char const *caller = request->module; + + rad_assert(module != NULL); + + RDEBUG2("Calling submodule %s to process data", module->type->name); + + request->module = module->type->name; + + switch (handler->stage) { + case INITIATE: + if (!module->type->session_init(module->instance, handler)) { + rcode = 0; + } + + break; + + case PROCESS: + /* + * The called function updates the EAP reply packet. + */ + if (!module->type->process || + !module->type->process(module->instance, handler)) { + rcode = 0; + } + + break; + + default: + /* Should never enter here */ + RDEBUG("Internal sanity check failed on EAP"); + rcode = 0; + break; + } + + request->module = caller; + return rcode; +} + +/** Process NAK data from EAP peer + * + */ +static eap_type_t eap_process_nak(rlm_eap_t *inst, REQUEST *request, + eap_type_t type, + eap_type_data_t *nak) +{ + unsigned int i; + VALUE_PAIR *vp; + eap_type_t method = PW_EAP_INVALID; + + /* + * The NAK data is the preferred EAP type(s) of + * the client. + * + * RFC 3748 says to list one or more proposed + * alternative types, one per octet, or to use + * 0 for no alternative. + */ + if (!nak->data) { + REDEBUG("Peer sent empty (invalid) NAK. " + "Can't select method to continue with"); + + return PW_EAP_INVALID; + } + + /* + * Pick one type out of the one they asked for, + * as they may have asked for many. + */ + vp = fr_pair_find_by_num(request->config, PW_EAP_TYPE, 0, TAG_ANY); + for (i = 0; i < nak->length; i++) { + /* + * Type 0 is valid, and means there are no + * common choices. + */ + if (nak->data[i] == 0) { + RDEBUG("Peer NAK'd indicating it is not willing to " + "continue "); + + return PW_EAP_INVALID; + } + + /* + * It is invalid to request identity, + * notification & nak in nak. + */ + if (nak->data[i] < PW_EAP_MD5) { + REDEBUG("Peer NAK'd asking for bad " + "type %s (%d)", + eap_type2name(nak->data[i]), + nak->data[i]); + + return PW_EAP_INVALID; + } + + if ((nak->data[i] >= PW_EAP_MAX_TYPES) || + !inst->methods[nak->data[i]]) { + RDEBUG2("Peer NAK'd asking for " + "unsupported EAP type %s (%d), skipping...", + eap_type2name(nak->data[i]), + nak->data[i]); + + continue; + } + + /* + * Prevent a firestorm if the client is confused. + */ + if (type == nak->data[i]) { + RDEBUG2("Peer NAK'd our request for " + "%s (%d) with a request for " + "%s (%d), skipping...", + eap_type2name(nak->data[i]), + nak->data[i], + 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; + } + + /* + * Enforce per-user configuration of EAP + * types. + */ + if (vp && (vp->vp_integer != nak->data[i])) { + RDEBUG2("Peer wants %s (%d), while we " + "require %s (%d), skipping", + eap_type2name(nak->data[i]), + nak->data[i], + eap_type2name(vp->vp_integer), + vp->vp_integer); + + continue; + } + + RDEBUG("Found mutually acceptable type %s (%d)", + eap_type2name(nak->data[i]), nak->data[i]); + + method = nak->data[i]; + + break; + } + + if (method == PW_EAP_INVALID) { + REDEBUG("No mutually acceptable types found"); + } + + return method; +} + +/** Select the correct callback based on a response + * + * Based on the EAP response from the supplicant, call the appropriate + * method callback. + * + * Default to the configured EAP-Type for all Unsupported EAP-Types. + * + * @param inst Configuration data for this instance of rlm_eap. + * @param handler State data that persists over multiple rounds of EAP. + * @return a status code. + */ +eap_rcode_t eap_method_select(rlm_eap_t *inst, eap_handler_t *handler) +{ + eap_type_data_t *type = &handler->eap_ds->response->type; + REQUEST *request = handler->request; + + eap_type_t next = inst->default_method; + VALUE_PAIR *vp; + + /* + * Don't trust anyone. + */ + if ((type->num == 0) || (type->num >= PW_EAP_MAX_TYPES)) { + REDEBUG("Peer sent EAP method number %d, which is outside known range", type->num); + + return EAP_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 && + !handler->request->parent->parent->home_server) { + RERROR("Multiple levels of TLS nesting are invalid"); + + return EAP_INVALID; + } + + RDEBUG2("Peer sent packet with method EAP %s (%d)", eap_type2name(type->num), type->num); + /* + * Figure out what to do. + */ + switch (type->num) { + case PW_EAP_IDENTITY: + /* + * Allow per-user configuration of EAP types. + */ + vp = fr_pair_find_by_num(handler->request->config, PW_EAP_TYPE, 0, + TAG_ANY); + if (vp) next = vp->vp_integer; + + /* + * Ensure it's valid. + */ + if ((next < PW_EAP_MD5) || + (next >= PW_EAP_MAX_TYPES) || + (!inst->methods[next])) { + REDEBUG2("Tried to start unsupported EAP type %s (%d)", + eap_type2name(next), next); + + return EAP_INVALID; + } + + do_initiate: + /* + * If any of these fail, we messed badly somewhere + */ + rad_assert(next >= PW_EAP_MD5); + rad_assert(next < PW_EAP_MAX_TYPES); + rad_assert(inst->methods[next]); + + handler->stage = INITIATE; + handler->type = next; + + if (eap_module_call(inst->methods[next], handler) == 0) { + REDEBUG2("Failed starting EAP %s (%d) session. EAP sub-module failed", + eap_type2name(next), next); + + return EAP_INVALID; + } + break; + + case PW_EAP_NAK: + /* + * Delete old data, if necessary. + */ + if (handler->opaque && handler->free_opaque) { + handler->free_opaque(handler->opaque); + handler->free_opaque = NULL; + handler->opaque = NULL; + } + + /* + * We got a NAK after the peer started doing a + * particular EAP type. That's rude, tell the + * peer to go away. + */ + if (handler->started) return EAP_INVALID; + + next = eap_process_nak(inst, handler->request, + handler->type, type); + + /* + * We probably want to return 'fail' here... + */ + if (!next) { + return EAP_INVALID; + } + + goto do_initiate; + + /* + * Key off of the configured sub-modules. + */ + default: + /* + * We haven't configured it, it doesn't exist. + */ + if (!inst->methods[type->num]) { + REDEBUG2("Client asked for unsupported EAP type %s (%d)", + eap_type2name(type->num), + type->num); + + return EAP_INVALID; + } + + rad_assert(handler->stage == PROCESS); + handler->type = type->num; + if (eap_module_call(inst->methods[type->num], + handler) == 0) { + REDEBUG2("Failed continuing EAP %s (%d) session. EAP sub-module failed", + eap_type2name(type->num), + type->num); + + return EAP_INVALID; + } + handler->started = true; + break; + } + + return EAP_OK; +} + + +/* + * compose EAP reply packet in EAP-Message attr of RADIUS. + * + * Set the RADIUS reply codes based on EAP request codes. Append + * any additonal VPs to RADIUS reply + */ +rlm_rcode_t eap_compose(eap_handler_t *handler) +{ + VALUE_PAIR *vp; + eap_packet_raw_t *eap_packet; + REQUEST *request; + EAP_DS *eap_ds; + eap_packet_t *reply; + int rcode; + +#ifndef NDEBUG + handler = talloc_get_type_abort(handler, eap_handler_t); + request = talloc_get_type_abort(handler->request, REQUEST); + eap_ds = talloc_get_type_abort(handler->eap_ds, EAP_DS); + reply = talloc_get_type_abort(eap_ds->request, eap_packet_t); +#else + request = handler->request; + eap_ds = handler->eap_ds; + reply = eap_ds->request; +#endif + + /* + * The Id for the EAP packet to the NAS wasn't set. + * Do so now. + */ + if (!eap_ds->set_request_id) { + /* + * Id serves to suppport request/response + * retransmission in the EAP layer and as such + * must be different for 'adjacent' packets + * except in case of success/failure-replies. + * + * RFC2716 (EAP-TLS) requires this to be + * incremented, RFC2284 only makes the above- + * mentioned restriction. + */ + reply->id = handler->eap_ds->response->id; + + switch (reply->code) { + /* + * The Id is a simple "ack" for success + * and failure. + * + * RFC 3748 section 4.2 says + * + * ... The Identifier field MUST match + * the Identifier field of the Response + * packet that it is sent in response + * to. + */ + case PW_EAP_SUCCESS: + case PW_EAP_FAILURE: + break; + + /* + * We've sent a response to their + * request, the Id is incremented. + */ + default: + ++reply->id; + } + } + + /* + * For Request & Response packets, set the EAP sub-type, + * if the EAP sub-module didn't already set it. + * + * This allows the TLS module to be "morphic", and means + * that the TTLS and PEAP modules can call it to do most + * of their dirty work. + */ + if (((eap_ds->request->code == PW_EAP_REQUEST) || + (eap_ds->request->code == PW_EAP_RESPONSE)) && + (eap_ds->request->type.num == 0)) { + rad_assert(handler->type >= PW_EAP_MD5); + rad_assert(handler->type < PW_EAP_MAX_TYPES); + + eap_ds->request->type.num = handler->type; + } + + if (eap_wireformat(reply) == EAP_INVALID) { + return RLM_MODULE_INVALID; + } + eap_packet = (eap_packet_raw_t *)reply->packet; + + vp = radius_pair_create(request->reply, &request->reply->vps, PW_EAP_MESSAGE, 0); + if (!vp) return RLM_MODULE_INVALID; + + vp->vp_length = eap_packet->length[0] * 256 + eap_packet->length[1]; + vp->vp_octets = talloc_steal(vp, reply->packet); + reply->packet = NULL; + + /* + * EAP-Message is always associated with + * Message-Authenticator but not vice-versa. + * + * Don't add a Message-Authenticator if it's already + * there. + */ + vp = fr_pair_find_by_num(request->reply->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY); + if (!vp) { + vp = fr_pair_afrom_num(request->reply, PW_MESSAGE_AUTHENTICATOR, 0); + vp->vp_length = AUTH_VECTOR_LEN; + vp->vp_octets = talloc_zero_array(vp, uint8_t, vp->vp_length); + fr_pair_add(&(request->reply->vps), vp); + } + + /* Set request reply code, but only if it's not already set. */ + rcode = RLM_MODULE_OK; + if (!request->reply->code) switch (reply->code) { + case PW_EAP_RESPONSE: + request->reply->code = PW_CODE_ACCESS_REJECT; + rcode = RLM_MODULE_REJECT; + break; + case PW_EAP_SUCCESS: + request->reply->code = PW_CODE_ACCESS_ACCEPT; + rcode = RLM_MODULE_OK; + break; + case PW_EAP_FAILURE: + request->reply->code = PW_CODE_ACCESS_REJECT; + rcode = RLM_MODULE_REJECT; + break; + case PW_EAP_REQUEST: + request->reply->code = PW_CODE_ACCESS_CHALLENGE; + rcode = RLM_MODULE_HANDLED; + break; + default: + /* + * When we're pulling MS-CHAPv2 out of EAP-MS-CHAPv2, + * we do so WITHOUT setting a reply code, as the + * request is being proxied. + */ + if (request->options & RAD_REQUEST_OPTION_PROXY_EAP) { + return RLM_MODULE_HANDLED; + } + + /* Should never enter here */ + REDEBUG("Reply code %d is unknown, rejecting the request", reply->code); + request->reply->code = PW_CODE_ACCESS_REJECT; + reply->code = PW_EAP_FAILURE; + rcode = RLM_MODULE_REJECT; + break; + } + + RDEBUG2("Sending EAP %s (code %i) ID %d length %i", + eap_codes[eap_packet->code], eap_packet->code, reply->id, + eap_packet->length[0] * 256 + eap_packet->length[1]); + + return rcode; +} + +/* + * Radius criteria, EAP-Message is invalid without Message-Authenticator + * For EAP_START, send Access-Challenge with EAP Identity request. + */ +int eap_start(rlm_eap_t *inst, REQUEST *request) +{ + VALUE_PAIR *vp, *proxy; + VALUE_PAIR *eap_msg; + + eap_msg = fr_pair_find_by_num(request->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY); + if (!eap_msg) { + RDEBUG2("No EAP-Message, not doing EAP"); + return EAP_NOOP; + } + + /* + * Look for EAP-Type = None (FreeRADIUS specific attribute) + * this allows you to NOT do EAP for some users. + */ + vp = fr_pair_find_by_num(request->packet->vps, PW_EAP_TYPE, 0, TAG_ANY); + if (vp && vp->vp_integer == 0) { + RDEBUG2("Found EAP-Message, but EAP-Type = None, so we're not doing EAP"); + return EAP_NOOP; + } + + /* + * http://www.freeradius.org/rfc/rfc2869.html#EAP-Message + * + * Checks for Message-Authenticator are handled by rad_recv(). + */ + + /* + * Check for a Proxy-To-Realm. Don't get excited over LOCAL + * realms (sigh). + */ + proxy = fr_pair_find_by_num(request->config, PW_PROXY_TO_REALM, 0, TAG_ANY); + if (proxy) { + REALM *realm; + + /* + * If it's a LOCAL realm, then we're not proxying + * to it. + */ + realm = realm_find(proxy->vp_strvalue); + if (!realm || (realm && (!realm->auth_pool))) { + proxy = NULL; + } + } + + /* + * Check the length before de-referencing the contents. + * + * Lengths of zero are required by the RFC for EAP-Start, + * but we've never seen them in practice. + * + * Lengths of two are what we see in practice as + * EAP-Starts. + */ + if ((eap_msg->vp_length == 0) || (eap_msg->vp_length == 2)) { + uint8_t *p; + + /* + * It's a valid EAP-Start, but the request + * was marked as being proxied. So we don't + * do EAP, as the home server will do it. + */ + if (proxy) { + do_proxy: + RDEBUG2("Request is supposed to be proxied to " + "Realm %s. Not doing EAP.", proxy->vp_strvalue); + return EAP_NOOP; + } + + RDEBUG2("Got EAP_START message"); + vp = fr_pair_afrom_num(request->reply, PW_EAP_MESSAGE, 0); + if (!vp) return EAP_FAIL; + fr_pair_add(&request->reply->vps, vp); + + /* + * Manually create an EAP Identity request + */ + vp->vp_length = 5; + vp->vp_octets = p = talloc_array(vp, uint8_t, vp->vp_length); + + p[0] = PW_EAP_REQUEST; + p[1] = 0; /* ID */ + p[2] = 0; + p[3] = 5; /* length */ + p[4] = PW_EAP_IDENTITY; + + request->reply->code = PW_CODE_ACCESS_CHALLENGE; + return EAP_FOUND; + } /* end of handling EAP-Start */ + + /* + * The EAP packet header is 4 bytes, plus one byte of + * EAP sub-type. Short packets are discarded, unless + * we're proxying. + */ + if (eap_msg->vp_length < (EAP_HEADER_LEN + 1)) { + if (proxy) goto do_proxy; + + RDEBUG2("Ignoring EAP-Message which is too short to be meaningful"); + return EAP_FAIL; + } + + /* + * Create an EAP-Type containing the EAP-type + * from the packet. + */ + vp = fr_pair_afrom_num(request->packet, PW_EAP_TYPE, 0); + if (vp) { + vp->vp_integer = eap_msg->vp_octets[4]; + fr_pair_add(&(request->packet->vps), vp); + } + + /* + * If the request was marked to be proxied, do it now. + * This is done after checking for a valid length + * (which may not be good), and after adding the EAP-Type + * attribute. This lets other modules selectively cancel + * proxying based on EAP-Type. + */ + if (proxy) goto do_proxy; + + /* + * From now on, we're supposed to be handling the + * EAP packet. We better understand it... + */ + + /* + * We're allowed only a few codes. Request, Response, + * Success, or Failure. + */ + if ((eap_msg->vp_octets[0] == 0) || + (eap_msg->vp_octets[0] >= PW_EAP_MAX_CODES)) { + RDEBUG2("Peer sent EAP packet with unknown code %i", eap_msg->vp_octets[0]); + } else { + RDEBUG2("Peer sent EAP %s (code %i) ID %d length %zu", + eap_codes[eap_msg->vp_octets[0]], + eap_msg->vp_octets[0], + eap_msg->vp_octets[1], + eap_msg->vp_length); + } + + /* + * We handle request and responses. The only other defined + * codes are success and fail. The client SHOULD NOT be + * sending success/fail packets to us, as it doesn't make + * sense. + */ + if ((eap_msg->vp_octets[0] != PW_EAP_REQUEST) && + (eap_msg->vp_octets[0] != PW_EAP_RESPONSE)) { + RDEBUG2("Ignoring EAP packet which we don't know how to handle"); + return EAP_FAIL; + } + + /* + * We've been told to ignore unknown EAP types, AND it's + * an unknown type. Return "NOOP", which will cause the + * mod_authorize() to return NOOP. + * + * EAP-Identity, Notification, and NAK are all handled + * internally, so they never have handlers. + */ + if ((eap_msg->vp_octets[4] >= PW_EAP_MD5) && + inst->ignore_unknown_types && + ((eap_msg->vp_octets[4] == 0) || + (eap_msg->vp_octets[4] >= PW_EAP_MAX_TYPES) || + (!inst->methods[eap_msg->vp_octets[4]]))) { + RDEBUG2("Ignoring Unknown EAP type"); + return EAP_NOOP; + } + + /* + * They're NAKing the EAP type we wanted to use, and + * asking for one which we don't support. + * + * NAK is code + id + length1 + length + NAK + * + requested EAP type(s). + * + * We know at this point that we can't handle the + * request. We could either return an EAP-Fail here, but + * it's not too critical. + * + * By returning "noop", we can ensure that authorize() + * returns NOOP, and another module may choose to proxy + * the request. + */ + if ((eap_msg->vp_octets[4] == PW_EAP_NAK) && + (eap_msg->vp_length >= (EAP_HEADER_LEN + 2)) && + inst->ignore_unknown_types && + ((eap_msg->vp_octets[5] == 0) || + (eap_msg->vp_octets[5] >= PW_EAP_MAX_TYPES) || + (!inst->methods[eap_msg->vp_octets[5]]))) { + RDEBUG2("Ignoring NAK with request for unknown EAP type"); + return EAP_NOOP; + } + + if ((eap_msg->vp_octets[4] == PW_EAP_TTLS) || + (eap_msg->vp_octets[4] == PW_EAP_PEAP)) { + RDEBUG2("Continuing tunnel setup"); + return EAP_OK; + } + /* + * We return ok in response to EAP identity + * This means we can write: + * + * eap { + * ok = return + * } + * ldap + * sql + * + * ...in the inner-tunnel, to avoid expensive and unnecessary SQL/LDAP lookups + */ + if (eap_msg->vp_octets[4] == PW_EAP_IDENTITY) { + RDEBUG2("EAP-Identity reply, returning 'ok' so we can short-circuit the rest of authorize"); + return EAP_OK; + } + + /* + * Later EAP messages are longer than the 'start' + * message, so if everything is OK, this function returns + * 'no start found', so that the rest of the EAP code can + * use the State attribute to match this EAP-Message to + * an ongoing conversation. + */ + RDEBUG2("No EAP Start, assuming it's an on-going EAP conversation"); + + return EAP_NOTFOUND; +} + +/* + * compose EAP FAILURE packet in EAP-Message + */ +void eap_fail(eap_handler_t *handler) +{ + /* + * Delete any previous replies. + */ + fr_pair_delete_by_num(&handler->request->reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY); + fr_pair_delete_by_num(&handler->request->reply->vps, PW_STATE, 0, TAG_ANY); + + talloc_free(handler->eap_ds->request); + handler->eap_ds->request = talloc_zero(handler->eap_ds, eap_packet_t); + handler->eap_ds->request->code = PW_EAP_FAILURE; + handler->finished = true; + eap_compose(handler); +} + +/* + * compose EAP SUCCESS packet in EAP-Message + */ +void eap_success(eap_handler_t *handler) +{ + handler->eap_ds->request->code = PW_EAP_SUCCESS; + handler->finished = true; + eap_compose(handler); +} + +/* + * Basic EAP packet verfications & validations + */ +static int eap_validation(REQUEST *request, eap_packet_raw_t **eap_packet_p) +{ + uint16_t len; + eap_packet_raw_t *eap_packet = *eap_packet_p; + + memcpy(&len, eap_packet->length, sizeof(uint16_t)); + len = ntohs(len); + + /* + * High level EAP packet checks + */ + if (len <= EAP_HEADER_LEN) { + RAUTH("EAP packet is too small: Ignoring it."); + return EAP_INVALID; + } + + if (eap_packet->code == PW_EAP_REQUEST) { + VALUE_PAIR *vp; + RAUTH("Unexpected EAP-Request. NAKing it."); + + vp = pair_make_reply("EAP-Message", "123456", T_OP_SET); + if (vp) { + uint8_t buffer[6]; + + buffer[0] = PW_EAP_RESPONSE; + buffer[1] = eap_packet->id; + buffer[2] = 0; + buffer[3] = 6; + buffer[4] = PW_EAP_NAK; + buffer[5] = 0; /* no overlapping EAP types */ + + fr_pair_value_memcpy(vp, buffer, 6); + } + + /* + * Ensure that the Access-Reject has a Message-Authenticator + */ + vp = fr_pair_find_by_num(request->reply->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY); + if (!vp) { + vp = fr_pair_afrom_num(request->reply, PW_MESSAGE_AUTHENTICATOR, 0); + vp->vp_length = AUTH_VECTOR_LEN; + vp->vp_octets = talloc_zero_array(vp, uint8_t, vp->vp_length); + fr_pair_add(&(request->reply->vps), vp); + } + request->reply->code = PW_CODE_ACCESS_REJECT; + + return EAP_INVALID; + } + + /* + * We only allow responses from the peer. The peer + * CANNOT ask us to authenticate outselves. + */ + if (eap_packet->code != PW_EAP_RESPONSE) { + RAUTH("Unexpected packet code %02x: Ignoring it.", eap_packet->code); + return EAP_INVALID; + } + + if ((eap_packet->data[0] <= 0) || + (eap_packet->data[0] >= PW_EAP_MAX_TYPES)) { + /* + * Handle expanded types by smashing them to + * normal types. + */ + if (eap_packet->data[0] == PW_EAP_EXPANDED_TYPE) { + uint8_t *p, *q; + + if (len <= (EAP_HEADER_LEN + 1 + 3 + 4)) { + RAUTH("Expanded EAP type is too short: ignoring the packet"); + return EAP_INVALID; + } + + if ((eap_packet->data[1] != 0) || + (eap_packet->data[2] != 0) || + (eap_packet->data[3] != 0)) { + RAUTH("Expanded EAP type has unknown Vendor-ID: ignoring the packet"); + return EAP_INVALID; + } + + if ((eap_packet->data[4] != 0) || + (eap_packet->data[5] != 0) || + (eap_packet->data[6] != 0)) { + RAUTH("Expanded EAP type has unknown Vendor-Type: ignoring the packet"); + return EAP_INVALID; + } + + if ((eap_packet->data[7] == 0) || + (eap_packet->data[7] >= PW_EAP_MAX_TYPES)) { + RAUTH("Unsupported Expanded EAP type %s (%u): ignoring the packet", + eap_type2name(eap_packet->data[7]), eap_packet->data[7]); + return EAP_INVALID; + } + + if (eap_packet->data[7] == PW_EAP_NAK) { + RAUTH("Unsupported Expanded EAP-NAK: ignoring the packet"); + return EAP_INVALID; + } + + /* + * Re-write the EAP packet to NOT have the expanded type. + */ + q = (uint8_t *) eap_packet; + memmove(q + EAP_HEADER_LEN, q + EAP_HEADER_LEN + 7, len - 7 - EAP_HEADER_LEN); + + p = talloc_realloc(talloc_parent(eap_packet), eap_packet, uint8_t, len - 7); + if (!p) { + RAUTH("Unsupported EAP type %s (%u): ignoring the packet", + eap_type2name(eap_packet->data[0]), eap_packet->data[0]); + return EAP_INVALID; + } + + len -= 7; + p[2] = (len >> 8) & 0xff; + p[3] = len & 0xff; + + *eap_packet_p = (eap_packet_raw_t *) p; + RWARN("Converting Expanded EAP to normal EAP."); + RWARN("Unnecessary use of Expanded EAP types is not recommended."); + + return EAP_VALID; + } + + RAUTH("Unsupported EAP type %s (%u): ignoring the packet", + eap_type2name(eap_packet->data[0]), eap_packet->data[0]); + return EAP_INVALID; + } + + /* we don't expect notification, but we send it */ + if (eap_packet->data[0] == PW_EAP_NOTIFICATION) { + RAUTH("Got NOTIFICATION, " + "Ignoring the packet"); + return EAP_INVALID; + } + + return EAP_VALID; +} + + +/* + * Get the user Identity only from EAP-Identity packets + */ +static char *eap_identity(REQUEST *request, eap_handler_t *handler, eap_packet_raw_t *eap_packet) +{ + int size; + uint16_t len; + char *identity; + + if ((!eap_packet) || + (eap_packet->code != PW_EAP_RESPONSE) || + (eap_packet->data[0] != PW_EAP_IDENTITY)) { + return NULL; + } + + memcpy(&len, eap_packet->length, sizeof(uint16_t)); + len = ntohs(len); + + if ((len <= 5) || (eap_packet->data[1] == 0x00)) { + REDEBUG("EAP-Identity Unknown"); + return NULL; + } + + if (len > 1024) { + REDEBUG("EAP-Identity too long"); + return NULL; + } + + size = len - 5; + identity = talloc_array(handler, char, size + 1); + memcpy(identity, &eap_packet->data[1], size); + identity[size] = '\0'; + + return identity; +} + + +/* + * Create our Request-Response data structure with the eap packet + */ +static EAP_DS *eap_buildds(eap_handler_t *handler, + eap_packet_raw_t **eap_packet_p) +{ + EAP_DS *eap_ds = NULL; + eap_packet_raw_t *eap_packet = *eap_packet_p; + int typelen; + uint16_t len; + + if ((eap_ds = eap_ds_alloc(handler)) == NULL) { + return NULL; + } + + eap_ds->response->packet = (uint8_t *) eap_packet; + (void) talloc_steal(eap_ds, eap_packet); + eap_ds->response->code = eap_packet->code; + eap_ds->response->id = eap_packet->id; + eap_ds->response->type.num = eap_packet->data[0]; + + memcpy(&len, eap_packet->length, sizeof(uint16_t)); + len = ntohs(len); + eap_ds->response->length = len; + + /* + * We've eaten the eap packet into the eap_ds. + */ + *eap_packet_p = NULL; + + /* + * First 5 bytes in eap, are code + id + length(2) + type. + * + * The rest is type-specific data. We skip type while + * getting typedata from data. + */ + typelen = len - 5/*code + id + length + type */; + if (typelen > 0) { + /* + * Since the packet contains the complete + * eap_packet, typedata will be a ptr in packet + * to its typedata + */ + eap_ds->response->type.data = eap_ds->response->packet + 5/*code+id+length+type*/; + eap_ds->response->type.length = typelen; + } else { + eap_ds->response->type.length = 0; + eap_ds->response->type.data = NULL; + } + + return eap_ds; +} + + +/* + * If identity response then create a fresh handler & fill the identity + * else handler MUST be in our list, get that. + * This handler creation cannot fail + * + * username contains REQUEST->username which might have been stripped. + * identity contains the one sent in EAP-Identity response + */ +eap_handler_t *eap_handler(rlm_eap_t *inst, eap_packet_raw_t **eap_packet_p, + REQUEST *request) +{ + eap_handler_t *handler = NULL; + eap_packet_raw_t *eap_packet; + VALUE_PAIR *vp; + + /* + * Ensure it's a valid EAP-Request, or EAP-Response. + */ + if (eap_validation(request, eap_packet_p) == EAP_INVALID) { + error: + talloc_free(*eap_packet_p); + *eap_packet_p = NULL; + return NULL; + } + + eap_packet = *eap_packet_p; + + /* + * eap_handler_t MUST be found in the list if it is not + * EAP-Identity response + */ + if (eap_packet->data[0] != PW_EAP_IDENTITY) { + handler = eaplist_find(inst, request, eap_packet); + if (!handler) { + /* Either send EAP_Identity or EAP-Fail */ + RDEBUG("Either EAP-request timed out OR EAP-response to an unknown EAP-request"); + goto error; + } + + /* + * Even more paranoia. Without this, some weird + * clients could do crazy things. + * + * It's ok to send EAP sub-type NAK in response + * to a request for a particular type, but it's NOT + * OK to blindly return data for another type. + */ + if ((eap_packet->data[0] != PW_EAP_NAK) && + (eap_packet->data[0] != handler->type)) { + RERROR("Response appears to match a previous request, but the EAP type is wrong"); + RERROR("We expected EAP type %s, but received type %s", + eap_type2name(handler->type), + eap_type2name(eap_packet->data[0])); + RERROR("Your Supplicant or NAS is probably broken"); + goto error; + } + + vp = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY); + if (!vp) { + /* + * NAS did not set the User-Name + * attribute, so we set it here and + * prepend it to the beginning of the + * request vps so that autz's work + * correctly + */ + RDEBUG2("Broken NAS did not set User-Name, setting from EAP Identity"); + vp = fr_pair_make(request->packet, &request->packet->vps, "User-Name", handler->identity, T_OP_EQ); + if (!vp) { + goto error; + } + } else { + /* + * A little more paranoia. If the NAS + * *did* set the User-Name, and it doesn't + * match the identity, (i.e. If they + * change their User-Name part way through + * the EAP transaction), then reject the + * request as the NAS is doing something + * funny. + */ + if (strncmp(handler->identity, vp->vp_strvalue, + MAX_STRING_LEN) != 0) { + RDEBUG("Identity does not match User-Name. Authentication failed"); + goto error; + } + } + } else { /* packet was EAP identity */ + handler = eap_handler_alloc(inst); + if (!handler) { + goto error; + } + + /* + * All fields in the handler are set to zero. + */ + handler->identity = eap_identity(request, handler, eap_packet); + if (!handler->identity) { + RDEBUG("Identity Unknown, authentication failed"); + error2: + talloc_free(handler); + goto error; + } + + vp = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY); + if (!vp) { + /* + * NAS did not set the User-Name + * attribute, so we set it here and + * prepend it to the beginning of the + * request vps so that autz's work + * correctly + */ + RWDEBUG2("NAS did not set User-Name. Setting it locally from EAP Identity"); + vp = fr_pair_make(request->packet, &request->packet->vps, "User-Name", handler->identity, T_OP_EQ); + if (!vp) { + goto error2; + } + } else { + /* + * Paranoia. If the NAS *did* set the + * User-Name, and it doesn't match the + * identity, the NAS is doing something + * funny, so reject the request. + */ + if (strncmp(handler->identity, vp->vp_strvalue, + MAX_STRING_LEN) != 0) { + RDEBUG("Identity does not match User-Name, setting from EAP Identity"); + goto error2; + } + } + } + + handler->eap_ds = eap_buildds(handler, eap_packet_p); + if (!handler->eap_ds) { + goto error2; + } + + handler->timestamp = request->timestamp; + handler->request = request; + return handler; +} diff --git a/src/modules/rlm_eap/eap.h b/src/modules/rlm_eap/eap.h new file mode 100644 index 0000000..b487c08 --- /dev/null +++ b/src/modules/rlm_eap/eap.h @@ -0,0 +1,154 @@ +/* + * eap.h Header file containing the interfaces for all EAP types. + * + * 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 2001 hereUare Communications, Inc. <raghud@hereuare.com> + * Copyright 2003 Alan DeKok <aland@freeradius.org> + * Copyright 2006 The FreeRADIUS server project + */ +#ifndef _EAP_H +#define _EAP_H + +RCSIDH(eap_h, "$Id$") + +#include <freeradius-devel/radiusd.h> +#include <freeradius-devel/modules.h> +#include <freeradius-devel/rad_assert.h> + +#include "eap_types.h" + +/* TLS configuration name */ +#define TLS_CONFIG_SECTION "tls-config" + +/* + * EAP_DS contains all the received/sending information + * response = Received EAP packet + * request = Sending EAP packet + * + * Note: We are authentication server, + * we get ONLY EAP-Responses and + * we send EAP-Request/EAP-success/EAP-failure + */ +typedef struct eap_ds { + eap_packet_t *response; + eap_packet_t *request; + int set_request_id; +} EAP_DS; + +/* + * Currently there are only 2 types + * of operations defined, + * apart from attach & detach for each EAP-Type. + */ +typedef enum operation_t { + INITIATE = 0, + PROCESS +} operation_t; + + +/* + * eap_handler_t is the interface for any EAP-Type. + * Each handler contains information for one specific EAP-Type. + * This way we don't need to change any interfaces in future. + * It is also a list of EAP-request handlers waiting for EAP-response + * eap_id = copy of the eap packet we sent to the + * + * next = pointer to next + * state = state attribute from the reply we sent + * state_len = length of data in the state attribute. + * src_ipaddr = client which sent us the RADIUS request containing + * this EAP conversation. + * eap_id = copy of EAP id we sent to the client. + * timestamp = timestamp when this handler was last used. + * identity = Identity, as obtained, from EAP-Identity response. + * request = RADIUS request data structure + * prev_eapds = Previous EAP request, for which eap_ds contains the response. + * eap_ds = Current EAP response. + * opaque = EAP-Type holds some data that corresponds to the current + * EAP-request/response + * free_opaque = To release memory held by opaque, + * when this handler is timedout & needs to be deleted. + * It is the responsibility of the specific EAP-TYPE + * to avoid any memory leaks in opaque + * Hence this pointer should be provided by the EAP-Type + * if opaque is not NULL + * status = finished/onhold/.. + */ +#define EAP_STATE_LEN (AUTH_VECTOR_LEN) +typedef struct _eap_handler { + struct _eap_handler *prev, *next; + uint8_t state[EAP_STATE_LEN]; + fr_ipaddr_t src_ipaddr; + + uint8_t eap_id; //!< EAP Identifier used to match + //!< requests and responses. + eap_type_t type; //!< EAP type number. + + time_t timestamp; + + REQUEST *request; + + char *identity; //!< User name from EAP-Identity + + EAP_DS *prev_eapds; + EAP_DS *eap_ds; + + void *opaque; + void (*free_opaque)(void *opaque); + void *inst_holder; + + int status; + + int stage; + + int trips; + + bool tls; + bool started; + bool finished; + VALUE_PAIR *certs; +} eap_handler_t; + +/* + * Interface to call EAP sub mdoules + */ +typedef struct rlm_eap_module { + char const *name; //!< The name of the sub-module + //!< (without rlm_ prefix). + int (*instantiate)(CONF_SECTION *conf, void **instance); //!< Create a new submodule instance. + int (*session_init)(void *instance, eap_handler_t *handler); //!< Initialise a new EAP session. + int (*process)(void *instance, eap_handler_t *handler); //!< Continue an EAP session. + int (*detach)(void *instance); //!< Destroy a submodule instance. +} rlm_eap_module_t; + +#define REQUEST_DATA_EAP_HANDLER (1) +#define REQUEST_DATA_EAP_TUNNEL_CALLBACK PW_EAP_MESSAGE +#define REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK ((PW_EAP_MESSAGE << 16) | PW_EAP_MSCHAPV2) +#define RAD_REQUEST_OPTION_PROXY_EAP (1 << 16) + +/* + * This is for tunneled callbacks + */ +typedef int (*eap_tunnel_callback_t)(eap_handler_t *handler, void *tls_session); + +typedef struct eap_tunnel_data_t { + void *tls_session; + eap_tunnel_callback_t callback; +} eap_tunnel_data_t; + +#endif /*_EAP_H*/ diff --git a/src/modules/rlm_eap/libeap/all.mk b/src/modules/rlm_eap/libeap/all.mk new file mode 100644 index 0000000..6a32129 --- /dev/null +++ b/src/modules/rlm_eap/libeap/all.mk @@ -0,0 +1,10 @@ +TARGET := libfreeradius-eap.a + +SOURCES := eapcommon.c eapcrypto.c eap_chbind.c eapsimlib.c fips186prf.c comp128.c +ifneq (${OPENSSL_LIBS},) +SOURCES += eap_tls.c mppe_keys.c +endif + +SRC_CFLAGS := -DEAPLIB + +SRC_INCDIRS := . .. diff --git a/src/modules/rlm_eap/libeap/comp128.c b/src/modules/rlm_eap/libeap/comp128.c new file mode 100644 index 0000000..e624877 --- /dev/null +++ b/src/modules/rlm_eap/libeap/comp128.c @@ -0,0 +1,460 @@ +/* + * This program is is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * $Id$ + * @file comp128.c + * @brief Implementations of comp128v1, comp128v2, comp128v3 algorithms + * + * Comp128v1 was inspired by code from: + * Marc Briceno <marc@scard.org>, Ian Goldberg <iang@cs.berkeley.edu>, + * and David Wagner <daw@cs.berkeley.edu> + * + * But it has been fully rewritten (Sylvain Munaut <tnt@246tNt.com>) from various PDFs found online + * describing the algorithm because the licence of the code referenced above was unclear. + * A comment snippet from the original code is included below, it describes where the doc came + * from and how the algorithm was reverse engineered. + * + * Comp128v2 & v3 is a port of the python code from: + * http://www.hackingprojects.net/ + * The author of the original code is Tamas Jos <tamas.jos@skelsec.com> + * + * @note The above GPL license only applies to comp128v1, the license for comp128v2 and comp128v3 is unknown. + * + * @copyright 2013 The FreeRADIUS server project + * @copyright 2013 Hacking projects [http://www.hackingprojects.net/] + * @copyright 2009 Sylvain Munaut <tnt@246tNt.com> + */ + +#include "comp128.h" +#include <stdio.h> +/* 512 bytes */ +static uint8_t const comp128v1_t0[] = { + 102, 177, 186, 162, 2, 156, 112, 75, 55, 25, 8, 12, 251, 193, 246, 188, + 109, 213, 151, 53, 42, 79, 191, 115, 233, 242, 164, 223, 209, 148, 108, 161, + 252, 37, 244, 47, 64, 211, 6, 237, 185, 160, 139, 113, 76, 138, 59, 70, + 67, 26, 13, 157, 63, 179, 221, 30, 214, 36, 166, 69, 152, 124, 207, 116, + 247, 194, 41, 84, 71, 1, 49, 14, 95, 35, 169, 21, 96, 78, 215, 225, + 182, 243, 28, 92, 201, 118, 4, 74, 248, 128, 17, 11, 146, 132, 245, 48, + 149, 90, 120, 39, 87, 230, 106, 232, 175, 19, 126, 190, 202, 141, 137, 176, + 250, 27, 101, 40, 219, 227, 58, 20, 51, 178, 98, 216, 140, 22, 32, 121, + 61, 103, 203, 72, 29, 110, 85, 212, 180, 204, 150, 183, 15, 66, 172, 196, + 56, 197, 158, 0, 100, 45, 153, 7, 144, 222, 163, 167, 60, 135, 210, 231, + 174, 165, 38, 249, 224, 34, 220, 229, 217, 208, 241, 68, 206, 189, 125, 255, + 239, 54, 168, 89, 123, 122, 73, 145, 117, 234, 143, 99, 129, 200, 192, 82, + 104, 170, 136, 235, 93, 81, 205, 173, 236, 94, 105, 52, 46, 228, 198, 5, + 57, 254, 97, 155, 142, 133, 199, 171, 187, 50, 65, 181, 127, 107, 147, 226, + 184, 218, 131, 33, 77, 86, 31, 44, 88, 62, 238, 18, 24, 43, 154, 23, + 80, 159, 134, 111, 9, 114, 3, 91, 16, 130, 83, 10, 195, 240, 253, 119, + 177, 102, 162, 186, 156, 2, 75, 112, 25, 55, 12, 8, 193, 251, 188, 246, + 213, 109, 53, 151, 79, 42, 115, 191, 242, 233, 223, 164, 148, 209, 161, 108, + 37, 252, 47, 244, 211, 64, 237, 6, 160, 185, 113, 139, 138, 76, 70, 59, + 26, 67, 157, 13, 179, 63, 30, 221, 36, 214, 69, 166, 124, 152, 116, 207, + 194, 247, 84, 41, 1, 71, 14, 49, 35, 95, 21, 169, 78, 96, 225, 215, + 243, 182, 92, 28, 118, 201, 74, 4, 128, 248, 11, 17, 132, 146, 48, 245, + 90, 149, 39, 120, 230, 87, 232, 106, 19, 175, 190, 126, 141, 202, 176, 137, + 27, 250, 40, 101, 227, 219, 20, 58, 178, 51, 216, 98, 22, 140, 121, 32, + 103, 61, 72, 203, 110, 29, 212, 85, 204, 180, 183, 150, 66, 15, 196, 172, + 197, 56, 0, 158, 45, 100, 7, 153, 222, 144, 167, 163, 135, 60, 231, 210, + 165, 174, 249, 38, 34, 224, 229, 220, 208, 217, 68, 241, 189, 206, 255, 125, + 54, 239, 89, 168, 122, 123, 145, 73, 234, 117, 99, 143, 200, 129, 82, 192, + 170, 104, 235, 136, 81, 93, 173, 205, 94, 236, 52, 105, 228, 46, 5, 198, + 254, 57, 155, 97, 133, 142, 171, 199, 50, 187, 181, 65, 107, 127, 226, 147, + 218, 184, 33, 131, 86, 77, 44, 31, 62, 88, 18, 238, 43, 24, 23, 154, + 159, 80, 111, 134, 114, 9, 91, 3, 130, 16, 10, 83, 240, 195, 119, 253}; + +/* 256 bytes */ +static uint8_t const comp128v1_t1[] = { + 19, 11, 80, 114, 43, 1, 69, 94, 39, 18, 127, 117, 97, 3, 85, 43, + 27, 124, 70, 83, 47, 71, 63, 10, 47, 89, 79, 4, 14, 59, 11, 5, + 35, 107, 103, 68, 21, 86, 36, 91, 85, 126, 32, 50, 109, 94, 120, 6, + 53, 79, 28, 45, 99, 95, 41, 34, 88, 68, 93, 55, 110, 125, 105, 20, + 90, 80, 76, 96, 23, 60, 89, 64, 121, 56, 14, 74, 101, 8, 19, 78, + 76, 66, 104, 46, 111, 50, 32, 3, 39, 0, 58, 25, 92, 22, 18, 51, + 57, 65, 119, 116, 22, 109, 7, 86, 59, 93, 62, 110, 78, 99, 77, 67, + 12, 113, 87, 98, 102, 5, 88, 33, 38, 56, 23, 8, 75, 45, 13, 75, + 95, 63, 28, 49, 123, 120, 20, 112, 44, 30, 15, 98, 106, 2, 103, 29, + 82, 107, 42, 124, 24, 30, 41, 16, 108, 100, 117, 40, 73, 40, 7, 114, + 82, 115, 36, 112, 12, 102, 100, 84, 92, 48, 72, 97, 9, 54, 55, 74, + 113, 123, 17, 26, 53, 58, 4, 9, 69, 122, 21, 118, 42, 60, 27, 73, + 118, 125, 34, 15, 65, 115, 84, 64, 62, 81, 70, 1, 24, 111, 121, 83, + 104, 81, 49, 127, 48, 105, 31, 10, 6, 91, 87, 37, 16, 54, 116, 126, + 31, 38, 13, 0, 72, 106, 77, 61, 26, 67, 46, 29, 96, 37, 61, 52, + 101, 17, 44, 108, 71, 52, 66, 57, 33, 51, 25, 90, 2, 119, 122, 35}; + +/* 128 bytes */ +static uint8_t const comp128v1_t2[] = { + 52, 50, 44, 6, 21, 49, 41, 59, 39, 51, 25, 32, 51, 47, 52, 43, + 37, 4, 40, 34, 61, 12, 28, 4, 58, 23, 8, 15, 12, 22, 9, 18, + 55, 10, 33, 35, 50, 1, 43, 3, 57, 13, 62, 14, 7, 42, 44, 59, + 62, 57, 27, 6, 8, 31, 26, 54, 41, 22, 45, 20, 39, 3, 16, 56, + 48, 2, 21, 28, 36, 42, 60, 33, 34, 18, 0, 11, 24, 10, 17, 61, + 29, 14, 45, 26, 55, 46, 11, 17, 54, 46, 9, 24, 30, 60, 32, 0, + 20, 38, 2, 30, 58, 35, 1, 16, 56, 40, 23, 48, 13, 19, 19, 27, + 31, 53, 47, 38, 63, 15, 49, 5, 37, 53, 25, 36, 63, 29, 5, 7}; + +/* 64 bytes */ +static uint8_t const comp128v1_t3[] = { + 1, 5, 29, 6, 25, 1, 18, 23, 17, 19, 0, 9, 24, 25, 6, 31, + 28, 20, 24, 30, 4, 27, 3, 13, 15, 16, 14, 18, 4, 3, 8, 9, + 20, 0, 12, 26, 21, 8, 28, 2, 29, 2, 15, 7, 11, 22, 14, 10, + 17, 21, 12, 30, 26, 27, 16, 31, 11, 7, 13, 23, 10, 5, 22, 19}; + +/* 32 bytes */ +static uint8_t const comp128v1_t4[] = { + 15, 12, 10, 4, 1, 14, 11, 7, 5, 0, 14, 7, 1, 2, 13, 8, + 10, 3, 4, 9, 6, 0, 3, 2, 5, 6, 8, 9, 11, 13, 15, 12}; + +static uint8_t const *_comp128_table[] = { comp128v1_t0, comp128v1_t1, comp128v1_t2, comp128v1_t3, comp128v1_t4 }; + +/* 256 bytes */ +static uint8_t const comp128v23_t0[] = { + 197, 235, 60, 151, 98, 96, 3, 100, 248, 118, 42, 117, 172, 211, 181, 203, + 61, 126, 156, 87, 149, 224, 55, 132, 186, 63, 238, 255, 85, 83, 152, 33, + 160, 184, 210, 219, 159, 11, 180, 194, 130, 212, 147, 5, 215, 92, 27, 46, + 113, 187, 52, 25, 185, 79, 221, 48, 70, 31, 101, 15, 195, 201, 50, 222, + 137, 233, 229, 106, 122, 183, 178, 177, 144, 207, 234, 182, 37, 254, 227, 231, + 54, 209, 133, 65, 202, 69, 237, 220, 189, 146, 120, 68, 21, 125, 38, 30, + 2, 155, 53, 196, 174, 176, 51, 246, 167, 76, 110, 20, 82, 121, 103, 112, + 56, 173, 49, 217, 252, 0, 114, 228, 123, 12, 93, 161, 253, 232, 240, 175, + 67, 128, 22, 158, 89, 18, 77, 109, 190, 17, 62, 4, 153, 163, 59, 145, + 138, 7, 74, 205, 10, 162, 80, 45, 104, 111, 150, 214, 154, 28, 191, 169, + 213, 88, 193, 198, 200, 245, 39, 164, 124, 84, 78, 1, 188, 170, 23, 86, + 226, 141, 32, 6, 131, 127, 199, 40, 135, 16, 57, 71, 91, 225, 168, 242, + 206, 97, 166, 44, 14, 90, 236, 239, 230, 244, 223, 108, 102, 119, 148, 251, + 29, 216, 8, 9, 249, 208, 24, 105, 94, 34, 64, 95, 115, 72, 134, 204, + 43, 247, 243, 218, 47, 58, 73, 107, 241, 179, 116, 66, 36, 143, 81, 250, + 139, 19, 13, 142, 140, 129, 192, 99, 171, 157, 136, 41, 75, 35, 165, 26}; + +/* 256 bytes */ +static uint8_t const comp128v23_t1[] = { + 170, 42, 95, 141, 109, 30, 71, 89, 26, 147, 231, 205, 239, 212, 124, 129, + 216, 79, 15, 185, 153, 14, 251, 162, 0, 241, 172, 197, 43, 10, 194, 235, + 6, 20, 72, 45, 143, 104, 161, 119, 41, 136, 38, 189, 135, 25, 93, 18, + 224, 171, 252, 195, 63, 19, 58, 165, 23, 55, 133, 254, 214, 144, 220, 178, + 156, 52, 110, 225, 97, 183, 140, 39, 53, 88, 219, 167, 16, 198, 62, 222, + 76, 139, 175, 94, 51, 134, 115, 22, 67, 1, 249, 217, 3, 5, 232, 138, + 31, 56, 116, 163, 70, 128, 234, 132, 229, 184, 244, 13, 34, 73, 233, 154, + 179, 131, 215, 236, 142, 223, 27, 57, 246, 108, 211, 8, 253, 85, 66, 245, + 193, 78, 190, 4, 17, 7, 150, 127, 152, 213, 37, 186, 2, 243, 46, 169, + 68, 101, 60, 174, 208, 158, 176, 69, 238, 191, 90, 83, 166, 125, 77, 59, + 21, 92, 49, 151, 168, 99, 9, 50, 146, 113, 117, 228, 65, 230, 40, 82, + 54, 237, 227, 102, 28, 36, 107, 24, 44, 126, 206, 201, 61, 114, 164, 207, + 181, 29, 91, 64, 221, 255, 48, 155, 192, 111, 180, 210, 182, 247, 203, 148, + 209, 98, 173, 11, 75, 123, 250, 118, 32, 47, 240, 202, 74, 177, 100, 80, + 196, 33, 248, 86, 157, 137, 120, 130, 84, 204, 122, 81, 242, 188, 200, 149, + 226, 218, 160, 187, 106, 35, 87, 105, 96, 145, 199, 159, 12, 121, 103, 112}; + +static inline void _comp128_compression_round(uint8_t *x, int n, const uint8_t *tbl) +{ + int i, j, m, a, b, y, z; + m = 4 - n; + for (i = 0; i < (1 << n); i++) { + for (j = 0; j < (1 << m); j++) { + a = j + i * (2 << m); + b = a + (1 << m); + y = (x[a] + (x[b] << 1)) & ((32 << m) - 1); + z = ((x[a] << 1) + x[b]) & ((32 << m) - 1); + x[a] = tbl[y]; + x[b] = tbl[z]; + } + } +} + +static inline void _comp128_compression(uint8_t *x) +{ + int n; + for (n = 0; n < 5; n++) { + _comp128_compression_round(x, n, _comp128_table[n]); + } +} + +static inline void _comp128_bitsfrombytes(uint8_t *x, uint8_t *bits) +{ + int i; + + memset(bits, 0x00, 128); + for (i = 0; i < 128; i++) { + if (x[i >> 2] & (1 << (3 - (i & 3)))) { + bits[i] = 1; + } + } +} + +static inline void _comp128_permutation(uint8_t *x, uint8_t *bits) +{ + int i; + memset(&x[16], 0x00, 16); + for (i = 0; i < 128; i++) { + x[(i >> 3) + 16] |= bits[(i * 17) & 127] << (7 - (i & 7)); + } +} + +/** Calculate comp128v1 sres and kc from ki and rand + * + * This code derived from a leaked document from the GSM standards. + * Some missing pieces were filled in by reverse-engineering a working SIM. + * We have verified that this is the correct COMP128 algorithm. + * + * The first page of the document identifies it as + * _Technical Information: GSM System Security Study_. + * 10-1617-01, 10th June 1988. + * The bottom of the title page is marked + * Racal Research Ltd. + * Worton Drive, Worton Grange Industrial Estate, + * Reading, Berks. RG2 0SB, England. + * Telephone: Reading (0734) 868601 Telex: 847152 + * The relevant bits are in Part I, Section 20 (pages 66--67). Enjoy! + * + * Note: There are three typos in the spec (discovered by reverse-engineering). + * First, "z = (2 * x[n] + x[n]) mod 2^(9-j)" should clearly read + * "z = (2 * x[m] + x[n]) mod 2^(9-j)". + * Second, the "k" loop in the "Form bits from bytes" section is severely + * botched: the k index should run only from 0 to 3, and clearly the range + * on "the (8-k)th bit of byte j" is also off (should be 0..7, not 1..8, + * to be consistent with the subsequent section). + * Third, SRES is taken from the first 8 nibbles of x[], not the last 8 as + * claimed in the document. (And the document doesn't specify how Kc is + * derived, but that was also easily discovered with reverse engineering.) + * All of these typos have been corrected in the following code. + * + * @param[out] sres 4 byte value derived from ki and rand. + * @param[out] kc 12 byte value derived from ki and rand. + * @param[in] ki known only by the SIM and AuC (us in this case). + * @param[in] rand 16 bytes of randomness. + */ +void comp128v1(uint8_t *sres, uint8_t *kc, uint8_t const *ki, uint8_t const *rand) +{ + int i; + uint8_t x[32], bits[128]; + + /* x[16-31] = RAND */ + memcpy(&x[16], rand, 16); + + /* + * Round 1-7 + */ + for (i=0; i < 7; i++) { + /* x[0-15] = Ki */ + memcpy(x, ki, 16); + + /* Compression */ + _comp128_compression(x); + + /* FormBitFromBytes */ + _comp128_bitsfrombytes(x, bits); + + /* Permutation */ + _comp128_permutation(x, bits); + } + + /* + * Round 8 (final) + * x[0-15] = Ki + */ + memcpy(x, ki, 16); + + /* Compression */ + _comp128_compression(x); + + /* Output stage */ + for (i = 0; i < 8; i += 2) { + sres[i >> 1] = x[i] << 4 | x[i + 1]; + } + + for (i = 0; i < 12; i += 2) { + kc[i>>1] = (x[i + 18] << 6) | + (x[i + 19] << 2) | + (x[i + 20] >> 2); + } + + kc[6] = (x[30] << 6) | (x[31] << 2); + kc[7] = 0; +} + +static void _comp128v23(uint8_t *rand, uint8_t const *kxor) +{ + uint8_t temp[16]; + uint8_t km_rm[32]; + + int j, i, k, z; + + memset(&temp, 0, sizeof(temp)); + memcpy(km_rm, rand, 16); + memcpy(km_rm + 16, kxor, 16); + memset(rand, 0, 16); + + for (i = 0; i < 5; i++) { + j = 0; + + for (z = 0; z < 16; z++) { + temp[z] = comp128v23_t0[comp128v23_t1[km_rm[16 + z]] ^ km_rm[z]]; + } + + while ((1 << i) > j) { + k = 0; + + while ((1 << (4 - i)) > k) { + km_rm[(((2 * k) + 1) << i) + j] = + comp128v23_t0[comp128v23_t1[temp[(k << i) + j]] ^ (km_rm[(k << i) + 16 + j])]; + km_rm[(k << (i + 1)) + j] = temp[(k << i) + j]; + k++; + } + j++; + } + } + + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) { + rand[i] = rand[i] ^ (((km_rm[(19 * (j + 8 * i) + 19) % 256 / 8] >> (3 * j + 3) % 8) & 1) << j); + } + } +} + +/** Calculate comp128v2 or comp128v3 sres and kc from ki and rand + * + * @param[out] sres 4 byte value derived from ki and rand. + * @param[out] kc 8 byte value derived from ki and rand. + * @param[in] ki known only by the SIM and AuC (us in this case). + * @param[in] rand 16 bytes of randomness. + * @param[in] v2 if true we use version comp128-2 else we use comp128-3. + + */ +void comp128v23(uint8_t *sres, uint8_t *kc, uint8_t const *ki, uint8_t const *rand, bool v2) +{ + uint8_t k_mix[16]; + uint8_t rand_mix[16]; + uint8_t katyvasz[16]; + uint8_t buffer[16]; + + /* Every day IM suffling... */ + int i; + + for (i = 0; i < 8; i++) { + k_mix[i] = ki[15 - i]; + k_mix[15 - i] = ki[i]; + } + + for (i = 0; i < 8; i++) { + rand_mix[i] = rand[15 - i]; + rand_mix[15 - i] = rand[i]; + } + + for (i = 0; i < 16; i++) { + katyvasz[i] = k_mix[i] ^ rand_mix[i]; + } + + for (i = 0; i < 8; i++) { + _comp128v23(rand_mix, katyvasz); + } + + for (i = 0; i < 16; i++) { + buffer[i] = rand_mix[15 - i]; + } + + if (v2) { + buffer[15] = 0x00; + buffer[14] = 4 * (buffer[14] >> 2); + } + + for (i = 0; i < 4; i++) { + buffer[8 + i - 4] = buffer[8 + i]; + buffer[8 + i] = buffer[8 + i + 4]; + } + + /* + * The algorithm uses 16 bytes until this point, but only 12 bytes are effective + * also 12 bytes coming out from the SIM card. + */ + memcpy(sres, buffer, 4); + memcpy(kc, buffer + 4, 8); +} + +#if 0 +#include <stdlib.h> +#include <ctype.h> +static int hextoint(char x) +{ + x = toupper(x); + if (x >= 'A' && x <= 'F') { + return x-'A' + 10; + } else if (x >= '0' && x <= '9') { + return x-'0'; + } + + fprintf(stderr, "Bad input.\n"); + + exit(1); +} + +int main(int argc, char **argv) +{ + uint8_t rand[16], key[16], sres[4], kc[8]; + int version; + int i; + + if ((argc != 4) || + (strlen(argv[1]) != 34) || (strlen(argv[2]) != 34) || + (strncmp(argv[1], "0x", 2) != 0) || (strncmp(argv[2], "0x", 2) != 0) || + !(version = atoi(argv[3]))) { + error: + fprintf(stderr, "Usage: %s 0x<key> 0x<rand> [1|2|3]\n", argv[0]); + exit(1); + } + + for (i = 0; i < 16; i++) { + key[i] = (hextoint(argv[1][(2 * i) + 2]) << 4) | hextoint(argv[1][(2 * i) + 3]); + } + + for (i = 0; i < 16; i++) { + rand[i] = (hextoint(argv[2][(2 * i) + 2]) << 4) | hextoint(argv[2][(2 * i) + 3]); + } + + switch (version) { + case 3: + comp128v23(sres, kc, key, rand, false); + break; + case 2: + comp128v23(sres, kc, key, rand, true); + break; + case 1: + comp128v1(sres, kc, key, rand); + break; + default: + fprintf(stderr, "Invalid version, must be 1,2 or 3"); + goto error; + } + + /* Output in vector format <Ki>,<rand>,<sres><Kc> */ + for (i = 0; i < 16; i++) { + printf("%02X", key[i]); + } + printf(","); + for (i = 0; i < 16; i++) { + printf("%02X", rand[i]); + } + printf(","); + for (i = 0; i < 4; i++) { + printf("%02X", sres[i]); + } + for (i = 0; i < 8; i++) { + printf("%02X", kc[i]); + } + printf("\n"); + + return 0; +} +#endif diff --git a/src/modules/rlm_eap/libeap/comp128.h b/src/modules/rlm_eap/libeap/comp128.h new file mode 100644 index 0000000..4cd2199 --- /dev/null +++ b/src/modules/rlm_eap/libeap/comp128.h @@ -0,0 +1,11 @@ +#ifndef _COMP128_H +#define _COMP128_H + +#include <string.h> +#include <stdint.h> +#include <stdbool.h> + +void comp128v1(uint8_t *sres, uint8_t *kc, const uint8_t *ki, const uint8_t *rand); +void comp128v23(uint8_t *sres, uint8_t *kc, uint8_t const *ki, uint8_t const *rand, bool v2); + +#endif diff --git a/src/modules/rlm_eap/libeap/eap_chbind.c b/src/modules/rlm_eap/libeap/eap_chbind.c new file mode 100644 index 0000000..21b2584 --- /dev/null +++ b/src/modules/rlm_eap/libeap/eap_chbind.c @@ -0,0 +1,290 @@ +/* + * eap_chbind.c + * + * 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 2014 Network RADIUS SARL + * Copyright 2014 The FreeRADIUS server project + */ + + +RCSID("$Id$") + +#include "eap_chbind.h" + +static bool chbind_build_response(REQUEST *request, CHBIND_REQ *chbind) +{ + int length; + size_t total; + uint8_t *ptr, *end; + VALUE_PAIR const *vp; + vp_cursor_t cursor; + + total = 0; + for (vp = fr_cursor_init(&cursor, &request->reply->vps); + vp != NULL; + vp = fr_cursor_next(&cursor)) { + /* + * Skip things which shouldn't be in channel bindings. + */ + if (vp->da->flags.encrypt != FLAG_ENCRYPT_NONE) continue; + if (!vp->da->vendor && (vp->da->attr == PW_MESSAGE_AUTHENTICATOR)) continue; + + total += 2 + vp->vp_length; + } + + /* + * No attributes: just send a 1-byte response code. + */ + if (!total) { + ptr = talloc_zero_array(chbind, uint8_t, 1); + } else { + ptr = talloc_zero_array(chbind, uint8_t, total + 4); + } + if (!ptr) return false; + chbind->response = (chbind_packet_t *) ptr; + + /* + * Set the response code. Default to "fail" if none was + * specified. + */ + vp = fr_pair_find_by_num(request->config, PW_CHBIND_RESPONSE_CODE, 0, TAG_ANY); + if (vp) { + ptr[0] = vp->vp_integer; + } else { + ptr[0] = CHBIND_CODE_FAILURE; + } + + if (!total) return true; /* nothing to encode */ + + /* Write the length field into the header */ + ptr[1] = (total >> 8) & 0xff; + ptr[2] = total & 0xff; + ptr[3] = CHBIND_NSID_RADIUS; + + RDEBUG("Sending chbind response: code %i", (int )(ptr[0])); + rdebug_pair_list(L_DBG_LVL_1, request, request->reply->vps, NULL); + + /* Encode the chbind attributes into the response */ + ptr += 4; + end = ptr + total; + for (vp = fr_cursor_init(&cursor, &request->reply->vps); + vp != NULL; + vp = fr_cursor_next(&cursor)) { + /* + * Skip things which shouldn't be in channel bindings. + */ + if (vp->da->flags.encrypt != FLAG_ENCRYPT_NONE) continue; + if (!vp->da->vendor && (vp->da->attr == PW_MESSAGE_AUTHENTICATOR)) continue; + + length = rad_vp2attr(NULL, NULL, NULL, &vp, ptr, end - ptr); + if (length < 0) continue; + ptr += length; + } + + return true; +} + + +/* + * Parse channel binding packet to obtain data for a specific + * NSID. + * + * See: + * http://tools.ietf.org/html/draft-ietf-emu-chbind-13#section-5.3.2 + */ +static size_t chbind_get_data(chbind_packet_t const *packet, + int desired_nsid, + uint8_t const **data) +{ + uint8_t const *ptr; + uint8_t const *end; + + if (packet->code != CHBIND_CODE_REQUEST) { + return 0; + } + + ptr = (uint8_t const *) packet; + end = ptr + talloc_array_length((uint8_t const *) packet); + + ptr++; /* skip the code at the start of the packet */ + while (ptr < end) { + uint8_t nsid; + size_t length; + + /* + * Need room for length(2) + NSID + data. + */ + if ((end - ptr) < 4) return 0; + + length = (ptr[0] << 8) | ptr[1]; + if (length == 0) return 0; + + if ((ptr + length + 3) > end) return 0; + + nsid = ptr[2]; + if (nsid == desired_nsid) { + ptr += 3; + *data = ptr; + return length; + } + + ptr += 3 + length; + } + + return 0; +} + + +PW_CODE chbind_process(REQUEST *request, CHBIND_REQ *chbind) +{ + PW_CODE rcode; + REQUEST *fake = NULL; + VALUE_PAIR *vp = NULL; + uint8_t const *attr_data; + size_t data_len = 0; + + /* check input parameters */ + rad_assert((request != NULL) && + (chbind != NULL) && + (chbind->request != NULL) && + (chbind->response == NULL)); + + /* Set-up the fake request */ + fake = request_alloc_fake(request); + 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) { + vp = fr_pair_copy(fake->packet, chbind->username); + fr_pair_add(&fake->packet->vps, vp); + fake->username = vp; + } + + /* + * Maybe copy the State over, too? + */ + + /* Add the channel binding attributes to the fake packet */ + data_len = chbind_get_data(chbind->request, CHBIND_NSID_RADIUS, &attr_data); + if (data_len) { + rad_assert(data_len <= talloc_array_length((uint8_t const *) chbind->request)); + + while (data_len > 0) { + int attr_len = rad_attr2vp(fake->packet, NULL, NULL, NULL, attr_data, data_len, &vp); + if (attr_len <= 0) { + /* If radaddr2vp fails, return NULL string for + channel binding response */ + talloc_free(fake); + return PW_CODE_ACCESS_ACCEPT; + } + if (vp) { + fr_pair_add(&fake->packet->vps, vp); + } + attr_data += attr_len; + data_len -= attr_len; + } + } + + /* + * Set virtual server based on configuration for channel + * bindings, this is hard-coded for now. + */ + fake->server = "channel_bindings"; + fake->packet->code = PW_CODE_ACCESS_REQUEST; + + switch (rad_virtual_server(fake)) { + /* If rad_authenticate succeeded, build a reply */ + case RLM_MODULE_OK: + case RLM_MODULE_HANDLED: + if (chbind_build_response(fake, chbind)) { + rcode = PW_CODE_ACCESS_ACCEPT; + break; + } + /* FALL-THROUGH */ + + /* If we got any other response from rad_authenticate, it maps to a reject */ + default: + rcode = PW_CODE_ACCESS_REJECT; + break; + } + + talloc_free(fake); + + return rcode; +} + +/* + * Handles multiple EAP-channel-binding Message attrs + * ie concatenates all to get the complete EAP-channel-binding packet. + */ +chbind_packet_t *eap_chbind_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps) +{ + size_t length; + uint8_t *ptr; + VALUE_PAIR *first, *vp; + chbind_packet_t *packet; + vp_cursor_t cursor; + + first = fr_pair_find_by_num(vps, PW_UKERNA_CHBIND, VENDORPEC_UKERNA, TAG_ANY); + if (!first) return NULL; + + /* + * Compute the total length of the channel binding data. + */ + length = 0; + fr_cursor_init(&cursor, &first); + while ((vp = fr_cursor_next_by_num(&cursor, PW_UKERNA_CHBIND, VENDORPEC_UKERNA, TAG_ANY))) { + length += vp->vp_length; + } + + if (length < 4) { + DEBUG("Invalid length %u for channel binding data", (unsigned int) length); + return NULL; + } + + /* + * Now that we know the length, allocate memory for the packet. + */ + ptr = talloc_zero_array(ctx, uint8_t, length); + if (!ptr) return NULL; + + /* + * Copy the data over to our packet. + */ + packet = (chbind_packet_t *) ptr; + fr_cursor_init(&cursor, &first); + while ((vp = fr_cursor_next_by_num(&cursor, PW_UKERNA_CHBIND, VENDORPEC_UKERNA, TAG_ANY))) { + memcpy(ptr, vp->vp_octets, vp->vp_length); + ptr += vp->vp_length; + } + + return packet; +} + +VALUE_PAIR *eap_chbind_packet2vp(RADIUS_PACKET *packet, chbind_packet_t *chbind) +{ + VALUE_PAIR *vp; + + if (!chbind) return NULL; /* don't produce garbage */ + + vp = fr_pair_afrom_num(packet, PW_UKERNA_CHBIND, VENDORPEC_UKERNA); + if (!vp) return NULL; + fr_pair_value_memcpy(vp, (uint8_t *) chbind, talloc_array_length((uint8_t *)chbind)); + + return vp; +} diff --git a/src/modules/rlm_eap/libeap/eap_chbind.h b/src/modules/rlm_eap/libeap/eap_chbind.h new file mode 100644 index 0000000..346b712 --- /dev/null +++ b/src/modules/rlm_eap/libeap/eap_chbind.h @@ -0,0 +1,64 @@ +/* + * eap_chbind.c + * + * 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 2014 Network RADIUS SARL + * Copyright 2014 The FreeRADIUS server project + */ + +#ifndef _EAP_CHBIND_H +#define _EAP_CHBIND_H + +RCSIDH(eap_chbind_h, "$Id$") + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <ctype.h> + +#include <freeradius-devel/radiusd.h> + +#include "eap.h" + +/* Structure to represent eap channel binding packet format */ +typedef struct chbind_packet_t { + uint8_t code; + uint8_t data[1]; +} chbind_packet_t; + +/* Structure to hold channel bindings req/resp information */ +typedef struct CHBIND_REQ { + VALUE_PAIR *username; /* the username */ + chbind_packet_t *request; /* channel binding request buffer */ + chbind_packet_t *response; /* channel binding response buffer */ +} CHBIND_REQ; + +/* Protocol constants */ +#define CHBIND_NSID_RADIUS 1 + +#define CHBIND_CODE_REQUEST 1 +#define CHBIND_CODE_SUCCESS 2 +#define CHBIND_CODE_FAILURE 3 + +/* Channel binding function prototypes */ +PW_CODE chbind_process(REQUEST *request, CHBIND_REQ *chbind_req); + +VALUE_PAIR *eap_chbind_packet2vp(RADIUS_PACKET *packet, chbind_packet_t *chbind); +chbind_packet_t *eap_chbind_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps); + +#endif /*_EAP_CHBIND_H*/ diff --git a/src/modules/rlm_eap/libeap/eap_sim.h b/src/modules/rlm_eap/libeap/eap_sim.h new file mode 100644 index 0000000..74dda25 --- /dev/null +++ b/src/modules/rlm_eap/libeap/eap_sim.h @@ -0,0 +1,122 @@ +/* + * eap_sim.h Header file containing the EAP-SIM types + * + * 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 Michael Richardson <mcr@sandelman.ottawa.on.ca> + * Copyright 2006 The FreeRADIUS server project + * + */ +#ifndef _EAP_SIM_H +#define _EAP_SIM_H + +RCSIDH(eap_sim_h, "$Id$") + +#include "eap_types.h" + +#define EAP_SIM_VERSION 0x0001 + +enum eapsim_subtype { + EAPSIM_START = 10, + EAPSIM_CHALLENGE = 11, + EAPSIM_NOTIFICATION = 12, + EAPSIM_REAUTH = 13, + EAPSIM_CLIENT_ERROR = 14, + EAPSIM_MAX_SUBTYPE = 15 +}; + +enum eapsim_clientstates { + EAPSIM_CLIENT_INIT = 0, + EAPSIM_CLIENT_START = 1, + EAPSIM_CLIENT_MAXSTATES +}; + +/* server states + * + * in server_start, we send a EAP-SIM Start message. + * + */ +enum eapsim_serverstates { + EAPSIM_SERVER_START = 0, + EAPSIM_SERVER_CHALLENGE = 1, + EAPSIM_SERVER_SUCCESS = 10, + EAPSIM_SERVER_MAXSTATES +}; + + +/* + * interfaces in eapsimlib.c + */ +int map_eapsim_basictypes(RADIUS_PACKET *r, eap_packet_t *ep); +char const *sim_state2name(enum eapsim_clientstates state, char *buf, int buflen); +char const *sim_subtype2name(enum eapsim_subtype subtype, char *buf, int buflen); +int unmap_eapsim_basictypes(RADIUS_PACKET *r, uint8_t *attr, unsigned int attrlen); + + +/************************/ +/* CRYPTO FUNCTIONS */ +/************************/ + +/* + * key derivation functions/structures + * + */ + +#define EAPSIM_SRES_SIZE 4 +#define EAPSIM_RAND_SIZE 16 +#define EAPSIM_KC_SIZE 8 +#define EAPSIM_CALCMAC_SIZE 20 +#define EAPSIM_NONCEMT_SIZE 16 +#define EAPSIM_AUTH_SIZE 16 + +struct eapsim_keys { + /* inputs */ + uint8_t identity[MAX_STRING_LEN]; + unsigned int identitylen; + uint8_t nonce_mt[EAPSIM_NONCEMT_SIZE]; + uint8_t rand[3][EAPSIM_RAND_SIZE]; + uint8_t sres[3][EAPSIM_SRES_SIZE]; + uint8_t Kc[3][EAPSIM_KC_SIZE]; + uint8_t versionlist[MAX_STRING_LEN]; + uint8_t versionlistlen; + uint8_t versionselect[2]; + + /* outputs */ + uint8_t master_key[20]; + uint8_t K_aut[EAPSIM_AUTH_SIZE]; + uint8_t K_encr[16]; + uint8_t msk[64]; + uint8_t emsk[64]; +}; + + +/* + * interfaces in eapsimlib.c + */ +int eapsim_checkmac(TALLOC_CTX *ctx, VALUE_PAIR *rvps, + uint8_t key[8], + uint8_t *extra, int extralen, + uint8_t calcmac[20]); + +/* + * in eapcrypto.c + */ +void eapsim_calculate_keys(struct eapsim_keys *ek); +void eapsim_dump_mk(struct eapsim_keys *ek); + + +#endif /* _EAP_SIM_H */ diff --git a/src/modules/rlm_eap/libeap/eap_tls.c b/src/modules/rlm_eap/libeap/eap_tls.c new file mode 100644 index 0000000..2f37663 --- /dev/null +++ b/src/modules/rlm_eap/libeap/eap_tls.c @@ -0,0 +1,1206 @@ + +/* + * eap_tls.c + * + * 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 2001 hereUare Communications, Inc. <raghud@hereuare.com> + * Copyright 2003 Alan DeKok <aland@freeradius.org> + * Copyright 2006 The FreeRADIUS server project + */ + +/* + * + * TLS Packet Format in EAP + * --- ------ ------ -- --- + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Code | Identifier | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Flags | TLS Message Length + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | TLS Message Length | TLS Data... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +RCSID("$Id$") +USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ + +#include <assert.h> + +#include "eap_tls.h" +/* + * Send an initial eap-tls request to the peer. + * + * Frame eap reply packet. + * len = header + type + tls_typedata + * tls_typedata = flags(Start (S) bit set, and no data) + * + * Once having received the peer's Identity, the EAP server MUST + * respond with an EAP-TLS/Start packet, which is an + * EAP-Request packet with EAP-Type=EAP-TLS, the Start (S) bit + * set, and no data. The EAP-TLS conversation will then begin, + * with the peer sending an EAP-Response packet with + * EAP-Type = EAP-TLS. The data field of that packet will + * be the TLS data. + * + * Fragment length is Framed-MTU - 4. + */ +tls_session_t *eaptls_session(eap_handler_t *handler, fr_tls_server_conf_t *tls_conf, bool client_cert, bool allow_tls13) +{ + tls_session_t *ssn; + REQUEST *request = handler->request; + + handler->tls = true; + + /* + * Every new session is started only from EAP-TLS-START. + * Before Sending EAP-TLS-START, open a new SSL session. + * Create all the required data structures & store them + * in Opaque. So that we can use these data structures + * when we get the response + */ + ssn = tls_new_session(handler, tls_conf, request, client_cert, allow_tls13); + if (!ssn) { + return NULL; + } + + /* + * Create a structure for all the items required to be + * verified for each client and set that as opaque data + * structure. + * + * NOTE: If we want to set each item sepearately then + * this index should be global. + */ + SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_HANDLER, (void *)handler); + SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_CONF, (void *)tls_conf); + SSL_set_ex_data(ssn->ssl, fr_tls_ex_index_certs, (void *)&(handler->certs)); + SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_IDENTITY, (void *)&(handler->identity)); +#ifdef HAVE_OPENSSL_OCSP_H + SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_STORE, (void *)tls_conf->ocsp_store); +#endif + SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_SSN, (void *)ssn); + SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_TALLOC, handler); + + return talloc_steal(handler, ssn); /* ssn */ +} + +/* + The S flag is set only within the EAP-TLS start message + sent from the EAP server to the peer. +*/ +int eaptls_start(EAP_DS *eap_ds, int peap_flag) +{ + EAPTLS_PACKET reply; + + reply.code = FR_TLS_START; + reply.length = TLS_HEADER_LEN + 1/*flags*/; + + reply.flags = peap_flag; + reply.flags = SET_START(reply.flags); + + reply.data = NULL; + reply.dlen = 0; + + eaptls_compose(eap_ds, &reply); + + return 1; +} + + +/** Send an EAP-TLS success + * + * Composes an EAP-TLS-Success. This is a message with code EAP_TLS_ESTABLISHED. + * It contains no cryptographic material, and is not protected. + * + * We add the MPPE keys here. These are used by the NAS. The supplicant + * will derive the same keys separately. + * + * @param handler handler of eap session that completed successfully. + * @param peap_flag to indicate PEAP version + * @return + * - 1 on success. + */ +int eaptls_success(eap_handler_t *handler, int peap_flag) +{ + EAPTLS_PACKET reply; + REQUEST *request = handler->request; + tls_session_t *tls_session = handler->opaque; + + handler->finished = true; + reply.code = FR_TLS_SUCCESS; + reply.length = TLS_HEADER_LEN; + reply.flags = peap_flag; + reply.data = NULL; + reply.dlen = 0; + + tls_success(tls_session, request); + + /* + * Call compose AFTER checking for cached data. + */ + eaptls_compose(handler->eap_ds, &reply); + + /* + * Automatically generate MPPE keying material. + */ + if (tls_session->label) { + uint8_t const *context = NULL; + size_t context_size = 0; +#ifdef TLS1_3_VERSION + uint8_t const context_tls13[] = { handler->type }; +#endif + + switch (SSL_version(tls_session->ssl)) { +#ifdef TLS1_3_VERSION + case TLS1_3_VERSION: + context = context_tls13; + context_size = sizeof(context_tls13); + tls_session->label = "EXPORTER_EAP_TLS_Key_Material"; + break; +#endif + case TLS1_2_VERSION: + case TLS1_1_VERSION: + case TLS1_VERSION: + break; + case SSL2_VERSION: + case SSL3_VERSION: + default: + /* Should never happen */ + rad_assert(0); + return 0; + break; + } + eaptls_gen_mppe_keys(request, + tls_session->ssl, tls_session->label, + context, context_size); + } else if (handler->type != PW_EAP_FAST) { + RWDEBUG("(TLS) EAP Not adding MPPE keys because there is no PRF label"); + } + + eaptls_gen_eap_key(handler); + + return 1; +} + +int eaptls_fail(eap_handler_t *handler, int peap_flag) +{ + EAPTLS_PACKET reply; + tls_session_t *tls_session = handler->opaque; + + handler->finished = true; + reply.code = FR_TLS_FAIL; + reply.length = TLS_HEADER_LEN; + reply.flags = peap_flag; + reply.data = NULL; + reply.dlen = 0; + + tls_fail(tls_session); + + eaptls_compose(handler->eap_ds, &reply); + + return 1; +} + +/* + A single TLS record may be up to 16384 octets in length, but a TLS + message may span multiple TLS records, and a TLS certificate message + may in principle be as long as 16MB. +*/ + +/* + * Frame the Dirty data that needs to be send to the client in an + * EAP-Request. We always embed the TLS-length in all EAP-TLS + * packets that we send, for easy reference purpose. Handle + * fragmentation and sending the next fragment etc. + */ +int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn) +{ + EAPTLS_PACKET reply; + unsigned int size; + unsigned int nlen; + unsigned int lbit = 0; + + /* This value determines whether we set (L)ength flag for + EVERY packet we send and add corresponding + "TLS Message Length" field. + + length_flag = true; + This means we include L flag and "TLS Msg Len" in EVERY + packet we send out. + + length_flag = false; + This means we include L flag and "TLS Msg Len" **ONLY** + in First packet of a fragment series. We do not use + it anywhere else. + + Having L flag in every packet is prefered. + + */ + if (ssn->length_flag) { + lbit = 4; + } + if (ssn->fragment == 0) { + ssn->tls_msg_len = ssn->dirty_out.used; + } + + reply.code = FR_TLS_REQUEST; + reply.flags = ssn->peap_flag; + + /* Send data, NOT more than the FRAGMENT size */ + if (ssn->dirty_out.used > ssn->mtu) { + size = ssn->mtu; + reply.flags = SET_MORE_FRAGMENTS(reply.flags); + /* Length MUST be included if it is the First Fragment */ + if (ssn->fragment == 0) { + lbit = 4; + } + ssn->fragment = 1; + } else { + size = ssn->dirty_out.used; + ssn->fragment = 0; + } + + reply.dlen = lbit + size; + reply.length = TLS_HEADER_LEN + 1/*flags*/ + reply.dlen; + + reply.data = talloc_array(eap_ds, uint8_t, reply.length); + if (!reply.data) return 0; + + if (lbit) { + nlen = htonl(ssn->tls_msg_len); + memcpy(reply.data, &nlen, lbit); + reply.flags = SET_LENGTH_INCLUDED(reply.flags); + } + (ssn->record_minus)(&ssn->dirty_out, reply.data + lbit, size); + + eaptls_compose(eap_ds, &reply); + talloc_free(reply.data); + reply.data = NULL; + + return 1; +} + + +/* + * Similarly, when the EAP server receives an EAP-Response with + * the M bit set, it MUST respond with an EAP-Request with + * EAP-Type=EAP-TLS and no data. This serves as a fragment ACK. + * + * In order to prevent errors in the processing of fragments, the + * EAP server MUST use increment the Identifier value for each + * fragment ACK contained within an EAP-Request, and the peer + * MUST include this Identifier value in the subsequent fragment + * contained within an EAP- Reponse. + * + * EAP server sends an ACK when it determines there are More + * fragments to receive to make the complete + * TLS-record/TLS-Message + */ +static int eaptls_send_ack(eap_handler_t *handler, int peap_flag) +{ + EAPTLS_PACKET reply; + REQUEST *request = handler->request; + + RDEBUG2("(TLS) EAP ACKing fragment, the peer should send more data."); + reply.code = FR_TLS_ACK; + reply.length = TLS_HEADER_LEN + 1/*flags*/; + reply.flags = peap_flag; + reply.data = NULL; + reply.dlen = 0; + + eaptls_compose(handler->eap_ds, &reply); + + return 1; +} + +/* + * The S flag is set only within the EAP-TLS start message sent + * from the EAP server to the peer. + * + * Similarly, when the EAP server receives an EAP-Response with + * the M bit set, it MUST respond with an EAP-Request with + * EAP-Type=EAP-TLS and no data. This serves as a fragment + * ACK. The EAP peer MUST wait. + */ +static fr_tls_status_t eaptls_verify(eap_handler_t *handler) +{ + EAP_DS *eap_ds = handler->eap_ds; + tls_session_t *tls_session = handler->opaque; + EAP_DS *prev_eap_ds = handler->prev_eapds; + eaptls_packet_t *eaptls_packet, *eaptls_prev = NULL; + REQUEST *request = handler->request; + size_t frag_len; + + /* + * We don't check ANY of the input parameters. It's all + * code which works together, so if something is wrong, + * we SHOULD core dump. + * + * e.g. if eap_ds is NULL, of if eap_ds->response is + * NULL, of if it's NOT an EAP-Response, or if the packet + * is too short. See eap_validation()., in ../../eap.c + * + * Also, eap_method_select() takes care of selecting the + * appropriate type, so we don't need to check + * eap_ds->response->type.num == PW_EAP_TLS, or anything + * else. + */ + eaptls_packet = (eaptls_packet_t *)eap_ds->response->type.data; + if (prev_eap_ds && prev_eap_ds->response) + eaptls_prev = (eaptls_packet_t *)prev_eap_ds->response->type.data; + + if (eaptls_packet) { + /* + * First output the flags (for debugging) + */ + RDEBUG3("(TLS) EAP Peer sent flags %c%c%c", + TLS_START(eaptls_packet->flags) ? 'S' : '-', + TLS_MORE_FRAGMENTS(eaptls_packet->flags) ? 'M' : '-', + TLS_LENGTH_INCLUDED(eaptls_packet->flags) ? 'L' : '-'); + } + + /* + * check for ACK + * + * If there's no TLS data, or there's 1 byte of TLS data, + * with the flags set to zero, then it's an ACK. + * + * Find if this is a reply to the previous request sent + */ + if ((!eaptls_packet) || + ((eap_ds->response->length == EAP_HEADER_LEN + 2) && + ((eaptls_packet->flags & 0xc0) == 0x00))) { + + if (prev_eap_ds && (prev_eap_ds->request->id == eap_ds->response->id)) { + return tls_ack_handler(handler->opaque, request); + } else { + REDEBUG("(TLS) EAP Received Unexpected ACK - rejection the connection"); + return FR_TLS_INVALID; + } + } + + /* + * We send TLS_START, but do not receive it. + */ + if (TLS_START(eaptls_packet->flags)) { + REDEBUG("(TLS) EAP Peer sent EAP-TLS Start message (only the server is allowed to do this)"); + return FR_TLS_INVALID; + } + + /* + * Calculate this fragment's length + */ + frag_len = eap_ds->response->length - + (EAP_HEADER_LEN + (TLS_LENGTH_INCLUDED(eaptls_packet->flags) ? 6 : 2)); + + /* + * The L bit (length included) is set to indicate the + * presence of the four octet TLS Message Length field, + * and MUST be set for the first fragment of a fragmented + * TLS message or set of messages. + * + * The M bit (more fragments) is set on all but the last + * fragment. + * + * The S bit (EAP-TLS start) is set in an EAP-TLS Start + * message. This differentiates the EAP-TLS Start message + * from a fragment acknowledgement. + */ + if (TLS_LENGTH_INCLUDED(eaptls_packet->flags)) { + size_t total_len = eaptls_packet->data[2] * 256 | eaptls_packet->data[3]; + + if (frag_len > total_len) { + RWDEBUG("(TLS) EAP Fragment length (%zu bytes) is greater than TLS record length (%zu bytes)", frag_len, + total_len); + } + + RDEBUG2("(TLS) EAP Peer says that the final record size will be %zu bytes", total_len); + if (TLS_MORE_FRAGMENTS(eaptls_packet->flags)) { + /* + * The supplicant is free to send fragments of wildly varying + * lengths, but the vast majority won't. + * + * In this calculation we take into account the fact that the future + * fragments are likely to be 4 bytes larger than the initial one + * as they won't contain the length field. + */ + if (frag_len + 4) { /* check for wrap, else clang scan gets excited */ + RDEBUG2("(TLS) EAP Expecting %i fragments", + (int)((((total_len - frag_len) + ((frag_len + 4) - 1)) / (frag_len + 4)) + 1)); + } + + /* + * FIRST_FRAGMENT is identified + * 1. If there is no previous EAP-response received. + * 2. If EAP-response received, then its M bit not set. + * (It is because Last fragment will not have M bit set) + */ + if (!prev_eap_ds || (!prev_eap_ds->response) || (!eaptls_prev) || + !TLS_MORE_FRAGMENTS(eaptls_prev->flags)) { + RDEBUG2("(TLS) EAP Got first TLS fragment (%zu bytes). Peer says more fragments " + "will follow", frag_len); + tls_session->tls_record_in_total_len = total_len; + tls_session->tls_record_in_recvd_len = frag_len; + + return FR_TLS_FIRST_FRAGMENT; + } + + RDEBUG2("(TLS) EAP Got additional fragment with length (%zu bytes). " + "Peer says more fragments will follow", frag_len); + + /* + * Check we've not exceeded the originally indicated TLS record size. + */ + tls_session->tls_record_in_recvd_len += frag_len; + if (tls_session->tls_record_in_recvd_len > tls_session->tls_record_in_total_len) { + RWDEBUG("(TLS) EAP Total received fragments (%zu bytes), exceeds " + "total data length (%zu bytes)", frag_len, total_len); + } + + return FR_TLS_MORE_FRAGMENTS_WITH_LENGTH; + } + + /* + * If it's a complete record, our fragment size should match the + * value of the four octet TLS length field. + */ + if (total_len != frag_len) { + RWDEBUG("(TLS) EAP Peer says no more fragments, but expected data length (%zu bytes) " + "does not match expected data length (%zu bytes)", total_len, frag_len); + } + + tls_session->tls_record_in_total_len = total_len; + tls_session->tls_record_in_recvd_len = frag_len; + RDEBUG2("(TLS) EAP Got all data (%zu bytes)", frag_len); + return FR_TLS_LENGTH_INCLUDED; + } + + /* + * The previous packet had the M flags set, but this one doesn't, + * this must be the final record fragment + */ + if ((eaptls_prev && TLS_MORE_FRAGMENTS(eaptls_prev->flags)) && !TLS_MORE_FRAGMENTS(eaptls_packet->flags)) { + RDEBUG2("(TLS) EAP Got final fragment (%zu bytes)", frag_len); + tls_session->tls_record_in_recvd_len += frag_len; + if (tls_session->tls_record_in_recvd_len != tls_session->tls_record_in_total_len) { + RWDEBUG("(TLS) EAP Total received record fragments (%zu bytes), does not equal expected " + "expected data length (%zu bytes)", + tls_session->tls_record_in_recvd_len, tls_session->tls_record_in_total_len); + } + } + + if (TLS_MORE_FRAGMENTS(eaptls_packet->flags)) { + RDEBUG2("(TLS) EAP Got additional fragment (%zu bytes). Peer says more fragments will follow", + frag_len); + tls_session->tls_record_in_recvd_len += frag_len; + if (tls_session->tls_record_in_recvd_len > tls_session->tls_record_in_total_len) { + RWDEBUG("(TLS) EAP Total received fragments (%zu bytes), exceeds " + "expected length (%zu bytes)", + tls_session->tls_record_in_recvd_len, tls_session->tls_record_in_total_len); + } + return FR_TLS_MORE_FRAGMENTS; + } + + /* + * None of the flags are set, but it's still a valid EAP-TLS packet. + */ + return FR_TLS_OK; +} + +/* + * EAPTLS_PACKET + * code = EAP-code + * id = EAP-id + * length = code + id + length + flags + tlsdata + * = 1 + 1 + 2 + 1 + X + * length = EAP-length - 1(EAP-Type = 1 octet) + * flags = EAP-typedata[0] (1 octet) + * dlen = EAP-typedata[1-4] (4 octets), if L flag set + * = length - 5(code+id+length+flags), otherwise + * data = EAP-typedata[5-n], if L flag set + * = EAP-typedata[1-n], otherwise + * packet = EAP-typedata (complete typedata) + * + * Points to consider during EAP-TLS data extraction + * 1. In the received packet, No data will be present incase of ACK-NAK + * 2. Incase if more fragments need to be received then ACK after retreiving this fragment. + * + * RFC 2716 Section 4.2. PPP EAP TLS Request Packet + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Code | Identifier | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Flags | TLS Message Length + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | TLS Message Length | TLS Data... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * The Length field is two octets and indicates the length of the EAP + * packet including the Code, Identifir, Length, Type, and TLS data + * fields. + */ +static EAPTLS_PACKET *eaptls_extract(REQUEST *request, EAP_DS *eap_ds, fr_tls_status_t status) +{ + EAPTLS_PACKET *tlspacket; + uint32_t data_len = 0; + uint32_t len = 0; + uint8_t *data = NULL; + + if (status == FR_TLS_INVALID) return NULL; + + /* + * The main EAP code & eaptls_verify() take care of + * ensuring that the packet is OK, and that we can + * extract the various fields we want. + * + * e.g. a TLS packet with zero data is allowed as an ACK, + * but we will never see it here, as we will simply + * send another fragment, instead of trying to extract + * the data. + * + * MUST have TLS type octet, followed by flags, followed + * by data. + */ + assert(eap_ds->response->length > 2); + + tlspacket = talloc(eap_ds, EAPTLS_PACKET); + if (!tlspacket) return NULL; + + /* + * Code & id for EAPTLS & EAP are same + * but eaptls_length = eap_length - 1(EAP-Type = 1 octet) + * + * length = code + id + length + type + tlsdata + * = 1 + 1 + 2 + 1 + X + */ + tlspacket->code = eap_ds->response->code; + tlspacket->id = eap_ds->response->id; + tlspacket->length = eap_ds->response->length - 1; /* EAP type */ + tlspacket->flags = eap_ds->response->type.data[0]; + + /* + * A quick sanity check of the flags. If we've been told + * that there's a length, and there isn't one, then stop. + */ + if (TLS_LENGTH_INCLUDED(tlspacket->flags) && + (tlspacket->length < 5)) { /* flags + TLS message length */ + REDEBUG("(TLS) EAP Invalid packet received: Length bit is set," + "but packet too short to contain length field"); + talloc_free(tlspacket); + return NULL; + } + + /* + * If the final TLS packet is larger than we can handle, die + * now. + * + * Likewise, if the EAP packet says N bytes, and the TLS + * packet says there's fewer bytes, it's a problem. + */ + if (TLS_LENGTH_INCLUDED(tlspacket->flags)) { + memcpy(&data_len, &eap_ds->response->type.data[1], 4); + data_len = ntohl(data_len); + if (data_len > MAX_RECORD_SIZE) { + REDEBUG("(TLS) EAP Reassembled data will be %u bytes, " + "greater than the size that we can handle (" STRINGIFY(MAX_RECORD_SIZE) " bytes)", + data_len); + talloc_free(tlspacket); + return NULL; + } + } + + switch (status) { + /* + * The TLS Message Length field is four octets, and + * provides the total length of the TLS message or set of + * messages that is being fragmented; this simplifies + * buffer allocation. + * + * Dynamic allocation of buffers as & when we know the + * length should solve the problem. + */ + case FR_TLS_FIRST_FRAGMENT: + case FR_TLS_LENGTH_INCLUDED: + case FR_TLS_MORE_FRAGMENTS_WITH_LENGTH: + if (tlspacket->length < 5) { /* flags + TLS message length */ + REDEBUG("(TLS) EAP Invalid packet received: Expected length, got none"); + talloc_free(tlspacket); + return NULL; + } + + /* + * Extract all the TLS fragments from the + * previous eap_ds Start appending this + * fragment to the above ds + */ + memcpy(&data_len, &eap_ds->response->type.data[1], sizeof(uint32_t)); + data_len = ntohl(data_len); + data = (eap_ds->response->type.data + 5/*flags+TLS-Length*/); + len = eap_ds->response->type.length - 5/*flags+TLS-Length*/; + + /* + * Hmm... this should be an error, too. + */ + if (data_len > len) { + data_len = len; + } + break; + + /* + * Data length is implicit, from the EAP header. + */ + case FR_TLS_MORE_FRAGMENTS: + case FR_TLS_OK: + data_len = eap_ds->response->type.length - 1/*flags*/; + data = eap_ds->response->type.data + 1/*flags*/; + break; + + default: + REDEBUG("(TLS) EAP Invalid packet received"); + talloc_free(tlspacket); + return NULL; + } + + tlspacket->dlen = data_len; + if (data_len) { + tlspacket->data = talloc_array(tlspacket, uint8_t, + data_len); + if (!tlspacket->data) { + talloc_free(tlspacket); + return NULL; + } + memcpy(tlspacket->data, data, data_len); + } + + return tlspacket; +} + + + +/* + * To process the TLS, + * INCOMING DATA: + * 1. EAP-TLS should get the compelete TLS data from the peer. + * 2. Store that data in a data structure with any other required info + * 3. Handle that data structure to the TLS module. + * 4. TLS module will perform its operations on the data and + * handle back to EAP-TLS + * + * OUTGOING DATA: + * 1. EAP-TLS if necessary will fragment it and send it to the + * destination. + * + * During EAP-TLS initialization, TLS Context object will be + * initialized and stored. For every new authentication + * requests, TLS will open a new session object and that session + * object should be maintained even after the session is + * completed for session resumption. (Probably later as a feature + * as we donot know who maintains these session objects ie, + * SSL_CTX (internally) or TLS module(explicitly). If TLS module, + * then how to let SSL API know about these sessions.) + */ +static fr_tls_status_t eaptls_operation(fr_tls_status_t status, eap_handler_t *handler) +{ + REQUEST *request = handler->request; + tls_session_t *tls_session = handler->opaque; + + if ((status == FR_TLS_MORE_FRAGMENTS) || + (status == FR_TLS_MORE_FRAGMENTS_WITH_LENGTH) || + (status == FR_TLS_FIRST_FRAGMENT)) { + /* + * Send the ACK. + */ + eaptls_send_ack(handler, tls_session->peap_flag); + return FR_TLS_HANDLED; + + } + + /* + * We have the complete TLS-data or TLS-message. + * + * Clean the dirty message. + * + * Authenticate the user and send + * Success/Failure. + * + * If more info + * is required then send another request. + */ + if (!tls_handshake_recv(handler->request, tls_session)) { + REDEBUG("(TLS) EAP Receive handshake failed during operation"); + tls_fail(tls_session); + return FR_TLS_FAIL; + } + +#ifdef TLS1_3_VERSION + /* + * https://tools.ietf.org/html/draft-ietf-emu-eap-tls13#section-2.5 + * + * We need to signal the other end that TLS negotiation + * is done. We can't send a zero-length application data + * message, so we send application data which is one byte + * of zero. + * + * Note this is only done for when there is no application + * data to be sent. So this is done always for EAP-TLS but + * notibly not for PEAP even on resumption. + */ + if ((SSL_version(tls_session->ssl) == TLS1_3_VERSION) && + (tls_session->client_cert_ok || tls_session->authentication_success || SSL_session_reused(tls_session->ssl))) { + if ((handler->type == PW_EAP_TLS) || SSL_session_reused(tls_session->ssl)) { + tls_session->authentication_success = true; + + RDEBUG("(TLS) EAP Sending final Commitment Message."); + tls_session->record_plus(&tls_session->clean_in, "\0", 1); + } + + tls_handshake_send(request, tls_session); + } +#endif + + /* + * FIXME: return success/fail. + * + * TLS proper can decide what to do, then. + */ + if (tls_session->dirty_out.used > 0) { + eaptls_request(handler->eap_ds, tls_session); + return FR_TLS_HANDLED; + } + + /* + * If there is no data to send i.e + * dirty_out.used <=0 and if the SSL + * handshake is finished. + */ + if (tls_session->is_init_finished) return FR_TLS_SUCCESS; + + /* + * If session is established, skip round-trip and + * try to process any inner tunnel data if present. + * + * This occurs for EAP-TTLS/PAP with TLSv1.3. + */ + if (!tls_session->is_init_finished && SSL_is_init_finished(tls_session->ssl)) { + /* + * Don't set is_init_finished, as that causes the + * rest of the code to make too many assumptions. + */ + return FR_TLS_OK; + } + + /* + * Who knows what happened... + */ + REDEBUG("(TLS) Cannot continue, as the peer is misbehaving."); + return FR_TLS_FAIL; +} + + +/* + * In the actual authentication first verify the packet and then create the data structure + */ +/* + * To process the TLS, + * INCOMING DATA: + * 1. EAP-TLS should get the compelete TLS data from the peer. + * 2. Store that data in a data structure with any other required info + * 3. Hand this data structure to the TLS module. + * 4. TLS module will perform its operations on the data and hands back to EAP-TLS + * OUTGOING DATA: + * 1. EAP-TLS if necessary will fragment it and send it to the destination. + * + * During EAP-TLS initialization, TLS Context object will be + * initialized and stored. For every new authentication + * requests, TLS will open a new session object and that + * session object SHOULD be maintained even after the session + * is completed, for session resumption. (Probably later as a + * feature, as we do not know who maintains these session + * objects ie, SSL_CTX (internally) or TLS module (explicitly). If + * TLS module, then how to let SSL API know about these + * sessions.) + */ + +/* + * Process an EAP request + */ +fr_tls_status_t eaptls_process(eap_handler_t *handler) +{ + tls_session_t *tls_session = (tls_session_t *) handler->opaque; + EAPTLS_PACKET *tlspacket; + fr_tls_status_t status; + REQUEST *request = handler->request; + + if (!request) return FR_TLS_FAIL; + + RDEBUG3("(TLS) EAP Continuing ..."); + + SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, request); + + if (handler->certs) fr_pair_add(&request->packet->vps, + fr_pair_list_copy(request->packet, handler->certs)); + + /* + * This case is when SSL generates Alert then we + * send that alert to the client and then send the EAP-Failure + */ + status = eaptls_verify(handler); + if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) { + REDEBUG("(TLS) EAP Verification failed with %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } else { + RDEBUG3("(TLS) EAP Verification says %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } + + switch (status) { + default: + case FR_TLS_INVALID: + case FR_TLS_FAIL: + + /* + * Success means that we're done the initial + * handshake. For TTLS, this means send stuff + * back to the client, and the client sends us + * more tunneled data. + */ + case FR_TLS_SUCCESS: + goto done; + + /* + * Normal TLS request, continue with the "get rest + * of fragments" phase. + */ + case FR_TLS_REQUEST: + eaptls_request(handler->eap_ds, tls_session); + status = FR_TLS_HANDLED; + goto done; + + /* + * The handshake is done, and we're in the "tunnel + * data" phase. + */ + case FR_TLS_OK: + RDEBUG2("(TLS) EAP Done initial handshake"); + + /* + * Get the rest of the fragments. + */ + case FR_TLS_FIRST_FRAGMENT: + case FR_TLS_MORE_FRAGMENTS: + case FR_TLS_LENGTH_INCLUDED: + case FR_TLS_MORE_FRAGMENTS_WITH_LENGTH: + break; + } + + /* + * Extract the TLS packet from the buffer. + */ + if ((tlspacket = eaptls_extract(request, handler->eap_ds, status)) == NULL) { + REDEBUG("(TLS) EAP Failed extracting TLS packet from EAP-Message"); + status = FR_TLS_FAIL; + goto done; + } + + /* + * Get the session struct from the handler + * + * update the dirty_in buffer + * + * NOTE: This buffer will contain partial data when M bit is set. + * + * CAUTION while reinitializing this buffer, it should be + * reinitialized only when this M bit is NOT set. + */ + if (tlspacket->dlen != + (tls_session->record_plus)(&tls_session->dirty_in, tlspacket->data, tlspacket->dlen)) { + talloc_free(tlspacket); + REDEBUG("(TLS) EAP Exceeded maximum record size"); + status = FR_TLS_FAIL; + goto done; + } + + /* + * No longer needed. + */ + talloc_free(tlspacket); + + /* + * SSL initalization is done. Return. + * + * The TLS data will be in the tls_session structure. + */ + if (tls_session->is_init_finished) { + /* + * The initialization may be finished, but if + * there more fragments coming, then send ACK, + * and get the caller to continue the + * conversation. + */ + if ((status == FR_TLS_MORE_FRAGMENTS) || + (status == FR_TLS_MORE_FRAGMENTS_WITH_LENGTH) || + (status == FR_TLS_FIRST_FRAGMENT)) { + /* + * Send the ACK. + */ + eaptls_send_ack(handler, tls_session->peap_flag); + RDEBUG2("(TLS) EAP Init is done, but tunneled data is fragmented"); + status = FR_TLS_HANDLED; + goto done; + } + + status = tls_application_data(tls_session, request); + goto done; + } + + /* + * Continue the handshake. + */ + status = eaptls_operation(status, handler); + if (status == FR_TLS_SUCCESS) { +#define MAX_SESSION_SIZE (256) + VALUE_PAIR *vps; + char buffer[2 * MAX_SESSION_SIZE + 1]; + + /* + * Restore the cached VPs before processing the + * application data. + */ + 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); + if (!vps) { + RWDEBUG("(TLS) EAP No information in cached session %s", buffer); + } else { + vp_cursor_t cursor; + VALUE_PAIR *vp; + fr_tls_server_conf_t *conf; + + RDEBUG("(TLS) EAP Adding cached attributes from session %s", buffer); + + conf = (fr_tls_server_conf_t *)SSL_get_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_CONF); + rad_assert(conf != NULL); + + /* + * The cbtls_get_session() function doesn't have + * access to sock->certs or handler->certs, which + * is where the certificates normally live. So + * the certs are all in the VPS list here, and + * have to be manually extracted. + */ + RINDENT(); + for (vp = fr_cursor_init(&cursor, &vps); + vp; + vp = fr_cursor_next(&cursor)) { + if (conf->cache_ht && fr_hash_table_finddata(conf->cache_ht, vp->da)) { + rdebug_pair(L_DBG_LVL_2, request, vp, "&session-state:"); + fr_pair_add(&request->state, fr_pair_copy(request->state_ctx, vp)); + continue; + } + + /* + * TLS-* attrs get added back to + * the request list. + */ + if ((vp->da->vendor == 0) && + (vp->da->attr >= PW_TLS_CERT_SERIAL) && + (vp->da->attr <= PW_TLS_CLIENT_CERT_SUBJECT_ALT_NAME_UPN)) { + /* + * Certs already exist. Don't re-add them. + */ + if (!handler->certs) { + rdebug_pair(L_DBG_LVL_2, request, vp, "&request:"); + fr_pair_add(&request->packet->vps, fr_pair_copy(request->packet, vp)); + } + + } else if ((vp->da->vendor == 0) && + (vp->da->attr == PW_EAP_TYPE)) { + /* + * EAP-Type gets added to + * the control list, so + * that we can sanity check it. + */ + rdebug_pair(L_DBG_LVL_2, request, vp, "&control:"); + fr_pair_add(&request->config, fr_pair_copy(request, vp)); + + } else { + + rdebug_pair(L_DBG_LVL_2, request, vp, "&reply:"); + fr_pair_add(&request->reply->vps, fr_pair_copy(request->reply, vp)); + } + } + REXDENT(); + } + } + + done: + SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, NULL); + + return status; +} + + +/* + * compose the TLS reply packet in the EAP reply typedata + */ +int eaptls_compose(EAP_DS *eap_ds, EAPTLS_PACKET *reply) +{ + uint8_t *ptr; + + /* + * Don't set eap_ds->request->type.num, as the main EAP + * handler will do that for us. This allows the TLS + * module to be called from TTLS & PEAP. + */ + + /* + * When the EAP server receives an EAP-Response with the + * M bit set, it MUST respond with an EAP-Request with + * EAP-Type=EAP-TLS and no data. This serves as a + * fragment ACK. The EAP peer MUST wait until it receives + * the EAP-Request before sending another fragment. + * + * In order to prevent errors in the processing of + * fragments, the EAP server MUST use increment the + * Identifier value for each fragment ACK contained + * within an EAP-Request, and the peer MUST include this + * Identifier value in the subsequent fragment contained + * within an EAP- Reponse. + */ + eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, + reply->length - TLS_HEADER_LEN + 1); + if (!eap_ds->request->type.data) return 0; + + /* EAPTLS Header length is excluded while computing EAP typelen */ + eap_ds->request->type.length = reply->length - TLS_HEADER_LEN; + + ptr = eap_ds->request->type.data; + *ptr++ = (uint8_t)(reply->flags & 0xFF); + + if (reply->dlen) memcpy(ptr, reply->data, reply->dlen); + + switch (reply->code) { + case FR_TLS_ACK: + case FR_TLS_START: + case FR_TLS_REQUEST: + eap_ds->request->code = PW_EAP_REQUEST; + break; + + case FR_TLS_SUCCESS: + eap_ds->request->code = PW_EAP_SUCCESS; + break; + + case FR_TLS_FAIL: + eap_ds->request->code = PW_EAP_FAILURE; + break; + + default: + /* Should never enter here */ + rad_assert(0); + break; + } + + return 1; +} + +/* + * Parse TLS configuration + * + * If the option given by 'attr' is set, we find the config section + * of that name and use that for the TLS configuration. If not, we + * fall back to compatibility mode and read the TLS options from + * the 'tls' section. + */ +fr_tls_server_conf_t *eaptls_conf_parse(CONF_SECTION *cs, char const *attr) +{ + char const *tls_conf_name; + CONF_PAIR *cp; + CONF_SECTION *parent; + CONF_SECTION *tls_cs; + fr_tls_server_conf_t *tls_conf; + + if (!cs) + return NULL; + + rad_assert(attr != NULL); + + parent = cf_item_parent(cf_section_to_item(cs)); + + cp = cf_pair_find(cs, attr); + if (cp) { + tls_conf_name = cf_pair_value(cp); + + tls_cs = cf_section_sub_find_name2(parent, TLS_CONFIG_SECTION, tls_conf_name); + + if (!tls_cs) { + ERROR("Cannot find tls config \"%s\"", tls_conf_name); + return NULL; + } + } else { + /* + * If we can't find the section given by the 'attr', we + * fall-back to looking for the "tls" section, as in + * previous versions. + * + * We don't fall back if the 'attr' is specified, but we can't + * find the section - that is just a config error. + */ + INFO("TLS section \"%s\" missing, trying to use legacy configuration", attr); + tls_cs = cf_section_sub_find(parent, "tls"); + } + + if (!tls_cs) + return NULL; + + tls_conf = tls_server_conf_parse(tls_cs); + + if (!tls_conf) + return NULL; + + /* + * The EAP RFC's say 1020, but we're less picky. + */ + if (tls_conf->fragment_size < 100) { + ERROR("Configured fragment size is too small, must be >= 100"); + return NULL; + } + + /* + * The maximum size for a RADIUS packet is 4096, + * minus the header (20), Message-Authenticator (18), + * and State (18), etc. results in about 4000 bytes of data + * that can be devoted *solely* to EAP. + */ + if (tls_conf->fragment_size > 4000) { + ERROR("Configured fragment size is too large, must be <= 4000"); + return NULL; + } + + /* + * Account for the EAP header (4), and the EAP-TLS header + * (6), as per Section 4.2 of RFC 2716. What's left is + * the maximum amount of data we read from a TLS buffer. + */ + tls_conf->fragment_size -= 10; + + return tls_conf; +} + diff --git a/src/modules/rlm_eap/libeap/eap_tls.h b/src/modules/rlm_eap/libeap/eap_tls.h new file mode 100644 index 0000000..8e5fc77 --- /dev/null +++ b/src/modules/rlm_eap/libeap/eap_tls.h @@ -0,0 +1,109 @@ +/* + * eap_tls.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 2001 hereUare Communications, Inc. <raghud@hereuare.com> + * Copyright 2003 Alan DeKok <aland@freeradius.org> + * Copyright 2006 The FreeRADIUS server project + */ +#ifndef _EAP_TLS_H +#define _EAP_TLS_H + +RCSIDH(eap_tls_h, "$Id$") +USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <netdb.h> +#include <fcntl.h> +#include <signal.h> + +#include <ctype.h> +#include <sys/time.h> +#include <arpa/inet.h> + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include <freeradius-devel/radiusd.h> +#include <freeradius-devel/tls.h> + +#include "eap.h" + +/* + * Externally exported TLS functions. + */ +fr_tls_status_t eaptls_process(eap_handler_t *handler); + +int eaptls_success(eap_handler_t *handler, int peap_flag) CC_HINT(nonnull); +int eaptls_fail(eap_handler_t *handler, int peap_flag) CC_HINT(nonnull); +int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn) CC_HINT(nonnull); + + +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 *label, uint8_t const *context, size_t context_size); +void eapttls_gen_challenge(SSL *s, uint8_t *buffer, size_t size); +void eaptls_gen_eap_key(eap_handler_t *handler); +void eap_fast_tls_gen_challenge(SSL *ssl, int version, uint8_t *buffer, size_t size, char const *prf_label) CC_HINT(nonnull); + +#define BUFFER_SIZE 1024 + +typedef enum tls_op { + EAP_TLS_START = 1, + EAP_TLS_ACK = 2, + EAP_TLS_SUCCESS = 3, + EAP_TLS_FAIL = 4, + EAP_TLS_ALERT = 9 +} tls_op_t; + +#define TLS_HEADER_LEN 4 + +typedef struct tls_packet_t { + uint8_t flags; + uint8_t data[1]; +} eaptls_packet_t; + +typedef struct tls_packet { + uint8_t code; + uint8_t id; + uint32_t length; + uint8_t flags; + uint8_t *data; + uint32_t dlen; + + //uint8_t *packet; /* Wired EAP-TLS packet as found in typdedata of eap_packet_t */ +} EAPTLS_PACKET; + + +/* EAP-TLS framework */ +EAPTLS_PACKET *eaptls_alloc(void); +void eaptls_free(EAPTLS_PACKET **eaptls_packet_ptr); +tls_session_t *eaptls_session(eap_handler_t *handler, fr_tls_server_conf_t *tls_conf, bool client_cert, bool allow_tls13); +int eaptls_start(EAP_DS *eap_ds, int peap); +int eaptls_compose(EAP_DS *eap_ds, EAPTLS_PACKET *reply); + +fr_tls_server_conf_t *eaptls_conf_parse(CONF_SECTION *cs, char const *key); + +#endif /*_EAP_TLS_H*/ diff --git a/src/modules/rlm_eap/libeap/eap_types.h b/src/modules/rlm_eap/libeap/eap_types.h new file mode 100644 index 0000000..c6568ff --- /dev/null +++ b/src/modules/rlm_eap/libeap/eap_types.h @@ -0,0 +1,162 @@ +/* + * eap_types.h Header file containing the interfaces for all EAP types. + * + * most contents moved from modules/rlm_eap/eap.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 2001 hereUare Communications, Inc. <raghud@hereuare.com> + * Copyright 2003 Alan DeKok <aland@freeradius.org> + * Copyright 2006 The FreeRADIUS server project + */ +#ifndef _EAP_TYPES_H +#define _EAP_TYPES_H + +RCSIDH(eap_methods_h, "$Id$") + +#include <freeradius-devel/radiusd.h> +#include <freeradius-devel/modules.h> + +/* Code (1) + Identifier (1) + Length (2) */ +#define EAP_HEADER_LEN 4 + +typedef enum eap_code { + PW_EAP_REQUEST = 1, + PW_EAP_RESPONSE, + PW_EAP_SUCCESS, + PW_EAP_FAILURE, + PW_EAP_MAX_CODES +} eap_code_t; + +typedef enum eap_method { + PW_EAP_INVALID = 0, /* 0 */ + PW_EAP_IDENTITY, /* 1 */ + PW_EAP_NOTIFICATION, /* 2 */ + PW_EAP_NAK, /* 3 */ + PW_EAP_MD5, /* 4 */ + PW_EAP_OTP, /* 5 */ + PW_EAP_GTC, /* 6 */ + PW_EAP_7, /* 7 - unused */ + PW_EAP_8, /* 8 - unused */ + PW_EAP_RSA_PUBLIC_KEY, /* 9 */ + PW_EAP_DSS_UNILATERAL, /* 10 */ + PW_EAP_KEA, /* 11 */ + PW_EAP_KEA_VALIDATE, /* 12 */ + PW_EAP_TLS, /* 13 */ + PW_EAP_DEFENDER_TOKEN, /* 14 */ + PW_EAP_RSA_SECURID, /* 15 */ + PW_EAP_ARCOT_SYSTEMS, /* 16 */ + PW_EAP_LEAP, /* 17 */ + PW_EAP_SIM, /* 18 */ + PW_EAP_SRP_SHA1, /* 19 */ + PW_EAP_20, /* 20 - unassigned */ + PW_EAP_TTLS, /* 21 */ + PW_EAP_REMOTE_ACCESS_SERVICE, /* 22 */ + PW_EAP_AKA, /* 23 */ + PW_EAP_3COM, /* 24 - should this be EAP-HP now? */ + PW_EAP_PEAP, /* 25 */ + PW_EAP_MSCHAPV2, /* 26 */ + PW_EAP_MAKE, /* 27 */ + PW_EAP_CRYPTOCARD, /* 28 */ + PW_EAP_CISCO_MSCHAPV2, /* 29 */ + PW_EAP_DYNAMID, /* 30 */ + PW_EAP_ROB, /* 31 */ + PW_EAP_POTP, /* 32 */ + PW_EAP_MS_ATLV, /* 33 */ + PW_EAP_SENTRINET, /* 34 */ + PW_EAP_ACTIONTEC, /* 35 */ + PW_EAP_COGENT_BIOMETRIC, /* 36 */ + PW_EAP_AIRFORTRESS, /* 37 */ + PW_EAP_TNC, /* 38 - fixme conflicts with HTTP DIGEST */ +// PW_EAP_HTTP_DIGEST, /* 38 */ + PW_EAP_SECURISUITE, /* 39 */ + PW_EAP_DEVICECONNECT, /* 40 */ + PW_EAP_SPEKE, /* 41 */ + PW_EAP_MOBAC, /* 42 */ + PW_EAP_FAST, /* 43 */ + PW_EAP_ZONELABS, /* 44 */ + PW_EAP_LINK, /* 45 */ + PW_EAP_PAX, /* 46 */ + PW_EAP_PSK, /* 47 */ + PW_EAP_SAKE, /* 48 */ + PW_EAP_IKEV2, /* 49 */ + PW_EAP_AKA2, /* 50 */ + PW_EAP_GPSK, /* 51 */ + PW_EAP_PWD, /* 52 */ + PW_EAP_EKE, /* 53 */ + PW_EAP_MAX_TYPES /* 54 - for validation */ +} eap_type_t; + +#define PW_EAP_EXPANDED_TYPE (254) + +typedef enum eap_rcode { + EAP_NOTFOUND, //!< EAP handler data not found. + EAP_FOUND, //!< EAP handler data found, continue. + EAP_OK, //!< Ok, continue. + EAP_FAIL, //!< Failed, don't reply. + EAP_NOOP, //!< Succeeded without doing anything. + EAP_INVALID, //!< Invalid, don't reply. + EAP_VALID, //!< Valid, continue. + EAP_MAX_RCODES +} eap_rcode_t; + +extern const FR_NAME_NUMBER eap_rcode_table[]; + +/** EAP-Type specific data + */ +typedef struct eap_type_data { + eap_type_t num; + size_t length; + uint8_t *data; +} eap_type_data_t; + +/** Structure to hold EAP data + * + * length = code + id + length + type + type.data + * = 1 + 1 + 2 + 1 + X + */ +typedef struct eap_packet { + eap_code_t code; + uint8_t id; + size_t length; + eap_type_data_t type; + + uint8_t *packet; +} eap_packet_t; + +/** Structure to represent packet format of eap *on wire* + */ +typedef struct eap_packet_raw { + uint8_t code; + uint8_t id; + uint8_t length[2]; + uint8_t data[1]; +} eap_packet_raw_t; + + +/* + * interfaces in eapcommon.c + */ +eap_type_t eap_name2type(char const *name); +char const *eap_type2name(eap_type_t method); +int eap_wireformat(eap_packet_t *reply); +int eap_basic_compose(RADIUS_PACKET *packet, eap_packet_t *reply); +VALUE_PAIR *eap_packet2vp(RADIUS_PACKET *packet, eap_packet_raw_t const *reply); +eap_packet_raw_t *eap_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps); +void eap_add_reply(REQUEST *request, char const *name, uint8_t const *value, int len); + +#endif /* _EAP_TYPES_H */ diff --git a/src/modules/rlm_eap/libeap/eapclient.h b/src/modules/rlm_eap/libeap/eapclient.h new file mode 100644 index 0000000..594007f --- /dev/null +++ b/src/modules/rlm_eap/libeap/eapclient.h @@ -0,0 +1,8 @@ +/* + * some of this seems like a repeat of rlm_eap, and needs to be better + * integrated, but as a client library, it deals with Request/Replies + * rather than with Replies -> new requests. + * + * Bare with me for a bit. + * + */ diff --git a/src/modules/rlm_eap/libeap/eapcommon.c b/src/modules/rlm_eap/libeap/eapcommon.c new file mode 100644 index 0000000..96db30b --- /dev/null +++ b/src/modules/rlm_eap/libeap/eapcommon.c @@ -0,0 +1,401 @@ +/* + * eapcommon.c rfc2284 & rfc2869 implementation + * + * code common to clients and to servers. + * + * 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 2000-2003,2006 The FreeRADIUS server project + * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com> + * Copyright 2003 Alan DeKok <aland@freeradius.org> + * Copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca> + */ +/* + * EAP PACKET FORMAT + * --- ------ ------ + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Code | Identifier | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Data ... + * +-+-+-+-+ + * + * + * EAP Request and Response Packet Format + * --- ------- --- -------- ------ ------ + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Code | Identifier | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Type-Data ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- + * + * + * EAP Success and Failure Packet Format + * --- ------- --- ------- ------ ------ + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Code | Identifier | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +RCSID("$Id$") + +#include <freeradius-devel/libradius.h> +#include <freeradius-devel/rad_assert.h> +#include "eap_types.h" + +const FR_NAME_NUMBER eap_rcode_table[] = { + { "notfound", EAP_NOTFOUND }, + { "found", EAP_OK }, + { "ok", EAP_FAIL }, + { "fail", EAP_NOOP }, + { "noop", EAP_INVALID }, + { "invalid", EAP_VALID }, + { "valid", EAP_MAX_RCODES }, + + { NULL , -1 } +}; + +/** Return an EAP-Type for a particular name + * + * Converts a name into an IANA EAP type. + * + * @param name to convert. + * @return The IANA EAP type or PW_EAP_INVALID if the name doesn't match any + * known types. + */ +eap_type_t eap_name2type(char const *name) +{ + DICT_VALUE *dv; + + dv = dict_valbyname(PW_EAP_TYPE, 0, name); + if (!dv) return PW_EAP_INVALID; + + if (dv->value >= PW_EAP_MAX_TYPES) return PW_EAP_INVALID; + + return dv->value; +} + +/** Return an EAP-name for a particular type + * + * Resolve + */ +char const *eap_type2name(eap_type_t method) +{ + DICT_VALUE *dv; + + dv = dict_valbyattr(PW_EAP_TYPE, 0, method); + if (dv) { + return dv->name; + } + + return "unknown"; +} + +/* + * EAP packet format to be sent over the wire + * + * i.e. code+id+length+data where data = null/type+typedata + * based on code. + * + * INPUT to function is reply->code + * reply->id + * reply->type - setup with data + * + * OUTPUT reply->packet is setup with wire format, and will + * be allocated to the right size. + * + */ +int eap_wireformat(eap_packet_t *reply) +{ + eap_packet_raw_t *header; + uint16_t total_length = 0; + + if (!reply) return EAP_INVALID; + + /* + * If reply->packet is set, then the wire format + * has already been calculated, just succeed. + */ + if(reply->packet != NULL) return EAP_VALID; + + total_length = EAP_HEADER_LEN; + if (reply->code < 3) { + total_length += 1/* EAP Method */; + if (reply->type.data && reply->type.length > 0) { + total_length += reply->type.length; + } + } + + reply->packet = talloc_array(reply, uint8_t, total_length); + header = (eap_packet_raw_t *)reply->packet; + if (!header) { + return EAP_INVALID; + } + + header->code = (reply->code & 0xFF); + header->id = (reply->id & 0xFF); + + total_length = htons(total_length); + memcpy(header->length, &total_length, sizeof(total_length)); + + /* + * Request and Response packets are special. + */ + if ((reply->code == PW_EAP_REQUEST) || + (reply->code == PW_EAP_RESPONSE)) { + header->data[0] = (reply->type.num & 0xFF); + + /* + * Here since we cannot know the typedata format and length + * + * Type_data is expected to be wired by each EAP-Type + * + * Zero length/No typedata is supported as long as + * type is defined + */ + if (reply->type.data && reply->type.length > 0) { + memcpy(&header->data[1], reply->type.data, reply->type.length); + talloc_free(reply->type.data); + reply->type.data = reply->packet + EAP_HEADER_LEN + 1/*EAPtype*/; + } + } + + return EAP_VALID; +} + + +/* + * compose EAP reply packet in EAP-Message attr of RADIUS. If + * EAP exceeds 253, frame it in multiple EAP-Message attrs. + */ +int eap_basic_compose(RADIUS_PACKET *packet, eap_packet_t *reply) +{ + VALUE_PAIR *vp; + eap_packet_raw_t *eap_packet; + int rcode; + + if (eap_wireformat(reply) == EAP_INVALID) { + return RLM_MODULE_INVALID; + } + eap_packet = (eap_packet_raw_t *)reply->packet; + + fr_pair_delete_by_num(&(packet->vps), PW_EAP_MESSAGE, 0, TAG_ANY); + + vp = eap_packet2vp(packet, eap_packet); + if (!vp) return RLM_MODULE_INVALID; + fr_pair_add(&(packet->vps), vp); + + /* + * EAP-Message is always associated with + * Message-Authenticator but not vice-versa. + * + * Don't add a Message-Authenticator if it's already + * there. + */ + vp = fr_pair_find_by_num(packet->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY); + if (!vp) { + vp = fr_pair_afrom_num(packet, PW_MESSAGE_AUTHENTICATOR, 0); + vp->vp_length = AUTH_VECTOR_LEN; + vp->vp_octets = talloc_zero_array(vp, uint8_t, vp->vp_length); + + fr_pair_add(&(packet->vps), vp); + } + + /* Set request reply code, but only if it's not already set. */ + rcode = RLM_MODULE_OK; + if (!packet->code) switch (reply->code) { + case PW_EAP_RESPONSE: + case PW_EAP_SUCCESS: + packet->code = PW_CODE_ACCESS_ACCEPT; + rcode = RLM_MODULE_HANDLED; + break; + case PW_EAP_FAILURE: + packet->code = PW_CODE_ACCESS_REJECT; + rcode = RLM_MODULE_REJECT; + break; + case PW_EAP_REQUEST: + packet->code = PW_CODE_ACCESS_CHALLENGE; + rcode = RLM_MODULE_HANDLED; + break; + default: + /* Should never enter here */ + ERROR("rlm_eap: reply code %d is unknown, Rejecting the request.", reply->code); + packet->code = PW_CODE_ACCESS_REJECT; + break; + } + + return rcode; +} + + +VALUE_PAIR *eap_packet2vp(RADIUS_PACKET *packet, eap_packet_raw_t const *eap) +{ + int total, size; + uint8_t const *ptr; + VALUE_PAIR *head = NULL; + VALUE_PAIR *vp; + vp_cursor_t out; + + total = eap->length[0] * 256 + eap->length[1]; + + if (total == 0) { + DEBUG("Asked to encode empty EAP-Message!"); + return NULL; + } + + ptr = (uint8_t const *) eap; + + fr_cursor_init(&out, &head); + do { + size = total; + if (size > 253) size = 253; + + vp = fr_pair_afrom_num(packet, PW_EAP_MESSAGE, 0); + if (!vp) { + fr_pair_list_free(&head); + return NULL; + } + fr_pair_value_memcpy(vp, ptr, size); + + fr_cursor_insert(&out, vp); + + ptr += size; + total -= size; + } while (total > 0); + + return head; +} + + +/* + * Handles multiple EAP-Message attrs + * ie concatenates all to get the complete EAP packet. + * + * NOTE: Sometimes Framed-MTU might contain the length of EAP-Message, + * refer fragmentation in rfc2869. + */ +eap_packet_raw_t *eap_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps) +{ + VALUE_PAIR *first, *i; + eap_packet_raw_t *eap_packet; + unsigned char *ptr; + uint16_t len; + int total_len; + vp_cursor_t cursor; + + /* + * Get only EAP-Message attribute list + */ + first = fr_pair_find_by_num(vps, PW_EAP_MESSAGE, 0, TAG_ANY); + if (!first) { + fr_strerror_printf("EAP-Message not found"); + return NULL; + } + + /* + * Sanity check the length before doing anything. + */ + if (first->vp_length < 4) { + fr_strerror_printf("EAP packet is too short"); + return NULL; + } + + /* + * Get the Actual length from the EAP packet + * First EAP-Message contains the EAP packet header + */ + memcpy(&len, first->vp_strvalue + 2, sizeof(len)); + len = ntohs(len); + + /* + * Take out even more weird things. + */ + if (len < 4) { + fr_strerror_printf("EAP packet has invalid length (less than 4 bytes)"); + return NULL; + } + + /* + * Sanity check the length, BEFORE allocating memory. + */ + total_len = 0; + fr_cursor_init(&cursor, &first); + while ((i = fr_cursor_next_by_num(&cursor, PW_EAP_MESSAGE, 0, TAG_ANY))) { + total_len += i->vp_length; + + if (total_len > len) { + fr_strerror_printf("Malformed EAP packet. Length in packet header %i, " + "does not match actual length %i", len, total_len); + return NULL; + } + } + + /* + * If the length is SMALLER, die, too. + */ + if (total_len < len) { + fr_strerror_printf("Malformed EAP packet. Length in packet header does not " + "match actual length"); + return NULL; + } + + /* + * Now that we know the lengths are OK, allocate memory. + */ + eap_packet = (eap_packet_raw_t *) talloc_zero_array(ctx, uint8_t, len); + if (!eap_packet) { + return NULL; + } + + /* + * Copy the data from EAP-Message's over to our EAP packet. + */ + ptr = (unsigned char *)eap_packet; + + /* RADIUS ensures order of attrs, so just concatenate all */ + fr_cursor_first(&cursor); + while ((i = fr_cursor_next_by_num(&cursor, PW_EAP_MESSAGE, 0, TAG_ANY))) { + memcpy(ptr, i->vp_strvalue, i->vp_length); + ptr += i->vp_length; + } + + return eap_packet; +} + +/* + * Add raw hex data to the reply. + */ +void eap_add_reply(REQUEST *request, + char const *name, uint8_t const *value, int len) +{ + VALUE_PAIR *vp; + + vp = pair_make_reply(name, NULL, T_OP_EQ); + if (!vp) { + REDEBUG("Did not create attribute %s: %s\n", + name, fr_strerror()); + return; + } + + fr_pair_value_memcpy(vp, value, len); +} diff --git a/src/modules/rlm_eap/libeap/eapcrypto.c b/src/modules/rlm_eap/libeap/eapcrypto.c new file mode 100644 index 0000000..f57714b --- /dev/null +++ b/src/modules/rlm_eap/libeap/eapcrypto.c @@ -0,0 +1,301 @@ +/* + * eapcrypto.c Common key derivation routines for EAP/SIM. + * + * The development of the EAP/SIM support was funded by Internet Foundation + * Austria (http://www.nic.at/ipa). + * + * 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 Michael Richardson <mcr@sandelman.ottawa.on.ca> + * Copyright 2003,2006 The FreeRADIUS server project + * + */ + +RCSID("$Id$") + +#include <stdio.h> +#include <stdlib.h> + +#include "eap_types.h" +#include "eap_sim.h" +#include <freeradius-devel/sha1.h> + +void eapsim_calculate_keys(struct eapsim_keys *ek) +{ + fr_sha1_ctx context; + uint8_t fk[160]; + unsigned char buf[256]; + unsigned char *p; + unsigned int blen; + + p = buf; + memcpy(p, ek->identity, ek->identitylen); p = p+ek->identitylen; + memcpy(p, ek->Kc[0], EAPSIM_KC_SIZE); p = p+EAPSIM_KC_SIZE; + memcpy(p, ek->Kc[1], EAPSIM_KC_SIZE); p = p+EAPSIM_KC_SIZE; + memcpy(p, ek->Kc[2], EAPSIM_KC_SIZE); p = p+EAPSIM_KC_SIZE; + memcpy(p, ek->nonce_mt, sizeof(ek->nonce_mt)); p=p+sizeof(ek->nonce_mt); + memcpy(p, ek->versionlist, ek->versionlistlen);p=p+ek->versionlistlen; + memcpy(p, ek->versionselect, sizeof(ek->versionselect)); p=p+sizeof(ek->versionselect); + /* *p++ = ek->versionselect[1]; */ + + blen = p - buf; + +#if defined(TEST_CASE) || defined(DUMP_EAPSIM_KEYS) + { + unsigned int i, j, k; + + j=0; k=0; + + printf("SHA1buffer was: "); + for (i = 0; i < blen; i++) { + if(j==4) { + printf("_"); + j=0; + } + if(k==20) { + printf("\n "); + k=0; + j=0; + } + j++; + k++; + + printf("%02x", buf[i]); + } + printf("\n"); + } +#endif + + + /* do the master key first */ + fr_sha1_init(&context); + fr_sha1_update(&context, buf, blen); + fr_sha1_final(ek->master_key, &context); + + /* + * now use the PRF to expand it, generated K_aut, K_encr, + * MSK and EMSK. + */ + fips186_2prf(ek->master_key, fk); + + /* split up the result */ + memcpy(ek->K_encr, fk + 0, 16); /* 128 bits for encryption */ + memcpy(ek->K_aut, fk + 16, EAPSIM_AUTH_SIZE); /*128 bits for auth */ + memcpy(ek->msk, fk + 32, 64); /* 64 bytes for Master Session Key */ + memcpy(ek->emsk, fk + 96, 64); /* 64- extended Master Session Key */ +} + + +void eapsim_dump_mk(struct eapsim_keys *ek) +{ + unsigned int i, j, k; + + printf("Input was: \n"); + printf(" identity: (len=%u)", ek->identitylen); + for (i = 0; i < ek->identitylen; i++) { + printf("%02x", ek->identity[i]); + } + + printf("\n nonce_mt: "); + for (i = 0; i < EAPSIM_NONCEMT_SIZE; i++) { + printf("%02x", ek->nonce_mt[i]); + } + + for (k = 0; k<3; k++) { + printf("\n rand%u: ", k); + for (i = 0; i < EAPSIM_RAND_SIZE; i++) { + printf("%02x", ek->rand[k][i]); + } + } + + for (k = 0; k<3; k++) { + printf("\n sres%u: ", k); + for (i = 0; i < EAPSIM_SRES_SIZE; i++) { + printf("%02x", ek->sres[k][i]); + } + } + + for (k = 0; k<3; k++) { + printf("\n Kc%u: ", k); + for (i = 0; i < EAPSIM_KC_SIZE; i++) { + printf("%02x", ek->Kc[k][i]); + } + } + + printf("\n versionlist[%d]: ",ek->versionlistlen); + for (i = 0; i < ek->versionlistlen; i++) { + printf("%02x", ek->versionlist[i]); + } + + printf("\n select %02x %02x\n", + ek->versionselect[0], + ek->versionselect[1]); + + printf("\n\nOutput\n"); + + printf("mk: "); + j=0; + for (i = 0; i < sizeof(ek->master_key); i++) { + if(j==4) { + printf("_"); + j=0; + } + j++; + + printf("%02x", ek->master_key[i]); + } + + printf("\nK_aut: "); + j=0; + for (i = 0; i < sizeof(ek->K_aut); i++) { + if(j==4) { + printf("_"); + j=0; + } + j++; + + printf("%02x", ek->K_aut[i]); + } + + printf("\nK_encr: "); + j=0; + for (i = 0; i < sizeof(ek->K_encr); i++) { + if(j==4) { + printf("_"); + j=0; + } + j++; + + printf("%02x", ek->K_encr[i]); + } + + printf("\nmsk: "); + j=0; k=0; + for (i = 0; i < sizeof(ek->msk); i++) { + if(k==20) { + printf("\n "); + k=0; + j=0; + } + if(j==4) { + printf("_"); + j=0; + } + k++; + j++; + + printf("%02x", ek->msk[i]); + } + printf("\nemsk: "); + j=0; k=0; + for (i = 0; i < sizeof(ek->emsk); i++) { + if(k==20) { + printf("\n "); + k=0; + j=0; + } + if(j==4) { + printf("_"); + j=0; + } + k++; + j++; + + printf("%02x", ek->emsk[i]); + } + printf("\n"); +} + +#ifdef TEST_CASE + +#include <assert.h> + +struct eapsim_keys inputkey1 = { + {'e', 'a', 'p', 's','i','m' }, + 6, + 0x4d, 0x6c, 0x40, 0xde, 0x48, 0x3a, 0xdd, 0x99, /* nonce_mt */ + 0x50, 0x90, 0x2c, 0x40, 0x24, 0xce, 0x76, 0x5e, + 0x89, 0xab, 0xcd, 0xef, 0x89, 0xab, 0xcd, 0xef, /* chalX */ + 0x89, 0xab, 0xcd, 0xef, 0x89, 0xab, 0xcd, 0xef, + 0x9a, 0xbc, 0xde, 0xf8, 0x9a, 0xbc, 0xde, 0xf8, + 0x9a, 0xbc, 0xde, 0xf8, 0x9a, 0xbc, 0xde, 0xf8, + 0xab, 0xcd, 0xef, 0x89, 0xab, 0xcd, 0xef, 0x89, + 0xab, 0xcd, 0xef, 0x89, 0xab, 0xcd, 0xef, 0x89, + 0x12, 0x34, 0xab, 0xcd, /* sresX */ + 0x12, 0x34, 0xab, 0xcd, + 0x23, 0x4a, 0xbc, 0xd1, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* Kc */ + 0x10, 0x21, 0x32, 0x43, 0x54, 0x65, 0x76, 0x87, + 0x30, 0x41, 0x52, 0x63, 0x74, 0x85, 0x96, 0xa7, + {0x00, 0x02, 0x00, 0x01}, + 4, + 0x00, 0x01 , +}; + +struct eapsim_keys inputkey2 = { + {'1','2','4','4','0','7','0','1','0','0','0','0','0','0','0','1','@','e','a','p','s','i','m','.','f','o','o'}, + 27, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, /* nonce_mt */ + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* chalX */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + + 0xd1, 0xd2, 0xd3, 0xd4, /* SRES 1 */ + 0xe1, 0xe2, 0xe3, 0xe4, + 0xf1, 0xf2, 0xf3, 0xf4, + + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* Kc */ + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + /* {0x00, 0x02, 0x00, 0x01}, */ + {0x00, 0x01}, + 2, + 0x00, 0x01 , +}; + + + +main(int argc, char *argv[]) +{ + struct eapsim_keys *ek; + + ek = &inputkey1; + + eapsim_calculate_keys(ek); + eapsim_dump_mk(ek); + + ek = &inputkey2; + + eapsim_calculate_keys(ek); + eapsim_dump_mk(ek); +} +#endif + + + + + + +/* + * Local Variables: + * c-style: bsd + * End: + */ diff --git a/src/modules/rlm_eap/libeap/eapsimlib.c b/src/modules/rlm_eap/libeap/eapsimlib.c new file mode 100644 index 0000000..67e21b2 --- /dev/null +++ b/src/modules/rlm_eap/libeap/eapsimlib.c @@ -0,0 +1,508 @@ +/* + * eapsimlib.c based upon draft-haverinen-pppext-eap-sim-11.txt. + * + * The development of the EAP/SIM support was funded by Internet Foundation + * Austria (http://www.nic.at/ipa). + * + * code common to EAP-SIM clients and to servers. + * + * 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 2000-2003,2006 The FreeRADIUS server project + * Copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca> + */ + +/* + * EAP-SIM PACKET FORMAT + * ------- ------ ------ + * + * EAP Request and Response Packet Format + * --- ------- --- -------- ------ ------ + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Code | Identifier | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | SIM-Type | SIM-Length | value ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * with SIM-Type/SIM-Length/Value... repeating. SIM-Length is in units + * of 32 bits, and includes the Sim-Type/Sim-Length fields. + * + * The SIM-Type's are mapped to PW_EAP_SIM_BASE+Sim-type and + * unmapped by these functions. + * + */ + +RCSID("$Id$") + +#include <freeradius-devel/libradius.h> +#include "eap_types.h" +#include "eap_sim.h" +#include <freeradius-devel/sha1.h> + +/* + * given a radius request with many attributes in the EAP-SIM range, build + * them all into a single EAP-SIM body. + * + */ +int map_eapsim_basictypes(RADIUS_PACKET *r, eap_packet_t *ep) +{ + VALUE_PAIR *vp; + int encoded_size; + uint8_t *encodedmsg, *attr; + unsigned int id, eapcode; + uint8_t *macspace; + uint8_t const *append; + int appendlen; + unsigned char subtype; + vp_cursor_t cursor; + + macspace = NULL; + append = NULL; + appendlen = 0; + + /* + * encodedmsg is now an EAP-SIM message. + * it might be too big for putting into an EAP-Type-SIM + * + */ + subtype = (vp = fr_pair_find_by_num(r->vps, PW_EAP_SIM_SUBTYPE, 0, TAG_ANY)) ? + vp->vp_integer : EAPSIM_START; + + id = (vp = fr_pair_find_by_num(r->vps, PW_EAP_ID, 0, TAG_ANY)) ? + vp->vp_integer : ((int)getpid() & 0xff); + + eapcode = (vp = fr_pair_find_by_num(r->vps, PW_EAP_CODE, 0, TAG_ANY)) ? + vp->vp_integer : PW_EAP_REQUEST; + + /* + * take a walk through the attribute list to see how much space + * that we need to encode all of this. + */ + encoded_size = 0; + for (vp = fr_cursor_init(&cursor, &r->vps); + vp; + vp = fr_cursor_next(&cursor)) { + int roundedlen; + int vplen; + + if ((vp->da->attr < PW_EAP_SIM_BASE) || (vp->da->attr >= (PW_EAP_SIM_BASE + 256))) { + continue; + } + + vplen = vp->vp_length; + + /* + * the AT_MAC attribute is a bit different, when we get to this + * attribute, we pull the contents out, save it for later + * processing, set the size to 16 bytes (plus 2 bytes padding). + * + * At this point, we only care about the size. + */ + if(vp->da->attr == PW_EAP_SIM_MAC) { + vplen = 18; + } + + /* round up to next multiple of 4, after taking in + * account the type and length bytes + */ + roundedlen = (vplen + 2 + 3) & ~3; + encoded_size += roundedlen; + } + + if (ep->code != PW_EAP_SUCCESS) { + ep->code = eapcode; + } + + ep->id = (id & 0xff); + ep->type.num = PW_EAP_SIM; + + /* + * if no attributes were found, do very little. + * + */ + if (encoded_size == 0) { + encodedmsg = talloc_array(ep, uint8_t, 3); + /* FIX: could be NULL */ + + encodedmsg[0] = subtype; + encodedmsg[1] = 0; + encodedmsg[2] = 0; + + ep->type.length = 3; + ep->type.data = encodedmsg; + + return 1; + } + + + /* + * figured out the length, so allocate some space for the results. + * + * Note that we do not bother going through an "EAP" stage, which + * is a bit strange compared to the unmap, which expects to see + * an EAP-SIM virtual attributes. + * + * EAP is 1-code, 1-identifier, 2-length, 1-type = 5 overhead. + * + * SIM code adds a subtype, and 2 bytes of reserved = 3. + * + */ + encoded_size += 3; + encodedmsg = talloc_array(ep, uint8_t, encoded_size); + if (!encodedmsg) { + return 0; + } + memset(encodedmsg, 0, encoded_size); + + /* + * now walk the attributes again, sticking them in. + * + * we go three bytes into the encoded message, because there are two + * bytes of reserved, and we will fill the "subtype" in later. + * + */ + attr = encodedmsg+3; + + for (vp = fr_cursor_first(&cursor); vp; vp = fr_cursor_next(&cursor)) { + int roundedlen; + + if(vp->da->attr < PW_EAP_SIM_BASE || + vp->da->attr >= PW_EAP_SIM_BASE + 256) { + continue; + } + + /* + * the AT_MAC attribute is a bit different, when we get to this + * attribute, we pull the contents out, save it for later + * processing, set the size to 16 bytes (plus 2 bytes padding). + * + * At this point, we put in zeros, and remember where the + * sixteen bytes go. + */ + if(vp->da->attr == PW_EAP_SIM_MAC) { + roundedlen = 20; + memset(&attr[2], 0, 18); + macspace = &attr[4]; + append = vp->vp_octets; + appendlen = vp->vp_length; + } else { + roundedlen = (vp->vp_length + 2 + 3) & ~3; + memset(attr, 0, roundedlen); + memcpy(&attr[2], vp->vp_strvalue, vp->vp_length); + } + attr[0] = vp->da->attr - PW_EAP_SIM_BASE; + attr[1] = roundedlen >> 2; + + attr += roundedlen; + } + + encodedmsg[0] = subtype; + + ep->type.length = encoded_size; + ep->type.data = encodedmsg; + + /* + * if macspace was set and we have a key, + * then we should calculate the HMAC-SHA1 of the resulting EAP-SIM + * packet, appended with the value of append. + */ + vp = fr_pair_find_by_num(r->vps, PW_EAP_SIM_KEY, 0, TAG_ANY); + if(macspace != NULL && vp != NULL) { + unsigned char *buffer; + eap_packet_raw_t *hdr; + uint16_t hmaclen, total_length = 0; + unsigned char sha1digest[20]; + + total_length = EAP_HEADER_LEN + 1 + encoded_size; + hmaclen = total_length + appendlen; + buffer = talloc_array(r, uint8_t, hmaclen); + hdr = (eap_packet_raw_t *) buffer; + if (!hdr) { + talloc_free(encodedmsg); + return 0; + } + + hdr->code = eapcode & 0xFF; + hdr->id = (id & 0xFF); + total_length = htons(total_length); + memcpy(hdr->length, &total_length, sizeof(total_length)); + + hdr->data[0] = PW_EAP_SIM; + + /* copy the data */ + memcpy(&hdr->data[1], encodedmsg, encoded_size); + + /* copy the nonce */ + memcpy(&hdr->data[encoded_size+1], append, appendlen); + + /* HMAC it! */ + fr_hmac_sha1(sha1digest, buffer, hmaclen, vp->vp_octets, vp->vp_length); + + /* done with the buffer, free it */ + talloc_free(buffer); + + /* now copy the digest to where it belongs in the AT_MAC */ + /* note that it is truncated to 128-bits */ + memcpy(macspace, sha1digest, 16); + } + + /* if we had an AT_MAC and no key, then fail */ + if ((macspace != NULL) && !vp) { + if (encodedmsg != NULL) { + talloc_free(encodedmsg); + } + + return 0; + } + + return 1; +} + +/* + * given a radius request with an EAP-SIM body, decode it into TLV pairs + * + * return value is true if it succeeded, false if there was something + * wrong and the packet should be discarded. + * + */ +int unmap_eapsim_basictypes(RADIUS_PACKET *r, + uint8_t *attr, unsigned int attrlen) +{ + VALUE_PAIR *newvp; + int eapsim_attribute; + unsigned int eapsim_len; + int es_attribute_count; + + es_attribute_count = 0; + + /* big enough to have even a single attribute */ + if (attrlen < 5) { + 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; + } + + newvp->vp_integer = attr[0]; + newvp->vp_length = 1; + fr_pair_add(&(r->vps), newvp); + + /* + * EAP-SIM has a 1 octet of subtype, and 2 octets + * reserved. + */ + attr += 3; + attrlen -= 3; + + /* + * Loop over each attribute. The format is: + * + * 1 octet of type + * 1 octet of length (value 1..255) + * ((4 * length) - 2) octets of data. + */ + while (attrlen > 0) { + uint8_t *p; + + if (attrlen < 2) { + fr_strerror_printf("EAP-Sim attribute %d too short: %d < 2", es_attribute_count, attrlen); + return 0; + } + + if (!attr[1]) { + fr_strerror_printf("EAP-Sim attribute %d (no.%d) has no data", attr[0], + es_attribute_count); + return 0; + } + + eapsim_attribute = attr[0]; + eapsim_len = attr[1] * 4; + + /* + * The length includes the 2-byte header. + */ + if (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; + } + + newvp = fr_pair_afrom_num(r, eapsim_attribute + PW_EAP_SIM_BASE, 0); + if (!newvp) { + /* + * RFC 4186 Section 8.1 says 0..127 are + * "non-skippable". If one such + * attribute is found and we don't + * understand it, the server has to send: + * + * EAP-Request/SIM/Notification packet with an + * (AT_NOTIFICATION code, which implies general failure ("General + * failure after authentication" (0), or "General failure" (16384), + * depending on the phase of the exchange), which terminates the + * authentication exchange. + */ + if (eapsim_attribute <= 127) { + fr_strerror_printf("Unknown mandatory attribute %d, failing", + eapsim_attribute); + return 0; + } + + } else { + /* + * It's known, ccount for header, and + * copy the value over. + */ + newvp->vp_length = eapsim_len - 2; + + newvp->vp_octets = p = talloc_array(newvp, uint8_t, newvp->vp_length); + memcpy(p, &attr[2], newvp->vp_length); + fr_pair_add(&(r->vps), newvp); + } + + /* advance pointers, decrement length */ + attr += eapsim_len; + attrlen -= eapsim_len; + es_attribute_count++; + } + + return 1; +} + +/* + * calculate the MAC for the EAP message, given the key. + * The "extra" will be appended to the EAP message and included in the + * HMAC. + * + */ +int eapsim_checkmac(TALLOC_CTX *ctx, VALUE_PAIR *rvps, uint8_t key[EAPSIM_AUTH_SIZE], uint8_t *extra, int extralen, + uint8_t calcmac[20]) +{ + int ret; + eap_packet_raw_t *e; + uint8_t *buffer; + int elen,len; + VALUE_PAIR *mac; + + mac = fr_pair_find_by_num(rvps, PW_EAP_SIM_MAC, 0, TAG_ANY); + + if(!mac || mac->vp_length != 18) { + /* can't check a packet with no AT_MAC attribute */ + return 0; + } + + /* get original copy of EAP message, note that it was sanitized + * to have a valid length, which we depend upon. + */ + e = eap_vp2packet(ctx, rvps); + if (!e) return 0; + + /* make copy big enough for everything */ + elen = (e->length[0] * 256) + e->length[1]; + len = elen + extralen; + + buffer = talloc_array(ctx, uint8_t, len); + if (!buffer) { + talloc_free(e); + return 0; + } + + memcpy(buffer, e, elen); + memcpy(buffer + elen, extra, extralen); + + /* + * now look for the AT_MAC attribute in the copy of the buffer + * and make sure that the checksum is zero. + * + */ + { + uint8_t *attr; + + /* first attribute is 8 bytes into the EAP packet. + * 4 bytes for EAP, 1 for type, 1 for subtype, 2 reserved. + */ + attr = buffer+8; + while(attr < (buffer+elen)) { + if (attr[0] == (PW_EAP_SIM_MAC - PW_EAP_SIM_BASE)) { + /* zero the data portion, after making sure + * the size is >=5. Maybe future versions. + * will use more bytes, so be liberal. + */ + if(attr[1] < 5) { + ret = 0; + goto done; + } + memset(&attr[4], 0, (attr[1]-1)*4); + } + /* advance the pointer */ + attr += attr[1]*4; + } + } + + /* now, HMAC-SHA1 it with the key. */ + fr_hmac_sha1(calcmac, buffer, len, key, 16); + + ret = memcmp(&mac->vp_strvalue[2], calcmac, 16) == 0 ? 1 : 0; + done: + talloc_free(e); + talloc_free(buffer); + return(ret); +} + +/* + * definitions changed to take a buffer for unknowns + * as this is more thread safe. + */ +static char const *simstates[] = { "init", "start", NULL }; + +char const *sim_state2name(enum eapsim_clientstates state, + char *statenamebuf, + int statenamebuflen) +{ + if(state >= EAPSIM_CLIENT_MAXSTATES) { + snprintf(statenamebuf, statenamebuflen, "eapstate:%d", state); + return statenamebuf; + } + + return simstates[state]; +} + +static char const *subtypes[] = { "subtype0", "subtype1", "subtype2", "subtype3", + "subtype4", "subtype5", "subtype6", "subtype7", + "subtype8", "subtype9", + "start", + "challenge", + "notification", + "reauth", + "client-error", + NULL }; + +char const *sim_subtype2name(enum eapsim_subtype subtype, char *subtypenamebuf, int subtypenamebuflen) +{ + if (subtype >= EAPSIM_MAX_SUBTYPE) { + snprintf(subtypenamebuf, subtypenamebuflen, "illegal-subtype:%d", subtype); + + return subtypenamebuf; + } + + return subtypes[subtype]; +} diff --git a/src/modules/rlm_eap/libeap/fips186prf.c b/src/modules/rlm_eap/libeap/fips186prf.c new file mode 100644 index 0000000..2002c62 --- /dev/null +++ b/src/modules/rlm_eap/libeap/fips186prf.c @@ -0,0 +1,270 @@ +/* + * fips186prf.c An implementation of the FIPS-186-2 SHA1-based PRF. + * + * The development of the EAP/SIM support was funded by Internet Foundation + * Austria (http://www.nic.at/ipa). + * + * This code was written from scratch by Michael Richardson, and it is + * dual licensed under both GPL and BSD. + * + * Version: $Id$ + * + * GPL notice: + * + * 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 + * + * BSD notice: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca> + * Copyright 2006 The FreeRADIUS server project + * + */ + +RCSID("$Id$") + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif + +#include <freeradius-devel/sha1.h> + +/* + * we do it in 8-bit chunks, because we have to keep the numbers + * in network byte order (i.e. MSB) + * + * make it a structure so that we can do structure assignments. + */ +typedef struct onesixty { + uint8_t p[20]; +} onesixty; + +static void onesixty_add_mod(onesixty *sum, onesixty *a, onesixty *b) +{ + uint32_t s; + int i, carry; + + carry = 0; + for(i=19; i>=0; i--) { +/* for(i=0; i<20; i++) { */ + s = a->p[i] + b->p[i] + carry; + sum->p[i] = s & 0xff; + carry = s >> 8; + } +} + +/* + * run the FIPS-186-2 PRF on the given Master Key (160 bits) + * in order to derive 1280 bits (160 bytes) of keying data from + * it. + * + * Given that in EAP-SIM, this is coming from a 64-bit Kc it seems + * like an awful lot of "randomness" to pull out.. (MCR) + * + */ +void fips186_2prf(uint8_t mk[20], uint8_t finalkey[160]) +{ + fr_sha1_ctx context; + int j; + onesixty xval, xkey, w_0, w_1, sum, one; + uint8_t *f; + uint8_t zeros[64]; + + /* + * let XKEY := MK, + * + * Step 3: For j = 0 to 3 do + * a. XVAL = XKEY + * b. w_0 = SHA1(XVAL) + * c. XKEY = (1 + XKEY + w_0) mod 2^160 + * d. XVAL = XKEY + * e. w_1 = SHA1(XVAL) + * f. XKEY = (1 + XKEY + w_1) mod 2^160 + * 3.3 x_j = w_0|w_1 + * + */ + memcpy(&xkey, mk, sizeof(xkey)); + + /* make the value 1 */ + memset(&one, 0, sizeof(one)); + one.p[19]=1; + + f=finalkey; + + for(j=0; j<4; j++) { + /* a. XVAL = XKEY */ + xval = xkey; + + /* b. w_0 = SHA1(XVAL) */ + fr_sha1_init(&context); + + memset(zeros + 20, 0, sizeof(zeros) - 20); + memcpy(zeros, xval.p, 20); +#ifndef WITH_OPENSSL_SHA1 + fr_sha1_transform(context.state, zeros); +#else + fr_sha1_transform(&context, zeros); +#endif + fr_sha1_final_no_len(w_0.p, &context); + + /* c. XKEY = (1 + XKEY + w_0) mod 2^160 */ + onesixty_add_mod(&sum, &xkey, &w_0); + onesixty_add_mod(&xkey, &sum, &one); + + /* d. XVAL = XKEY */ + xval = xkey; + + /* e. w_1 = SHA1(XVAL) */ + fr_sha1_init(&context); + + memset(zeros + 20, 0, sizeof(zeros) - 20); + memcpy(zeros, xval.p, 20); +#ifndef WITH_OPENSSL_SHA1 + fr_sha1_transform(context.state, zeros); +#else + fr_sha1_transform(&context, zeros); +#endif + fr_sha1_final_no_len(w_1.p, &context); + + /* f. XKEY = (1 + XKEY + w_1) mod 2^160 */ + onesixty_add_mod(&sum, &xkey, &w_1); + onesixty_add_mod(&xkey, &sum, &one); + + /* now store it away */ + memcpy(f, &w_0, 20); + f += 20; + + memcpy(f, &w_1, 20); + f += 20; + } +} + +/* + * test vectors + * from http://csrc.nist.gov/CryptoToolkit/dss/Examples-1024bit.pdf + * + * page 5 + * + * XKEY= bd029bbe 7f51960b cf9edb2b 61f06f0f eb5a38b6 + * XSEED= 00000000 00000000 00000000 00000000 00000000 + * + * + * The first loop through step 3.2 provides: + * + * XVAL= bd029bbe 7f51960b cf9edb2b 61f06f0f eb5a38b6 + * + * Using the routine in Appendix 3.3, Constructing The Function G From SHA-1, + * in step 3.2.b of the Change Notice algorithm for computing values of x + * provides: + * + * w[0]= 2070b322 3dba372f de1c0ffc 7b2e3b49 8b260614 + * + * + * The following value is the updated XKEY value from step 3.2.c: + * + * XKEY= dd734ee0 bd0bcd3b adbaeb27 dd1eaa59 76803ecb + * + * The second loop through step 3.2 provides: + * + * XVAL= dd734ee0 bd0bcd3b adbaeb27 dd1eaa59 76803ecb + * + * Using the routine in Appendix 3.3, Constructing The Function G From SHA-1, + * in step 3.2.b of the Change Notice algorithm for computing values of x + * provides: + * + * w[1]= 3c6c18ba cb0f6c55 babb1378 8e20d737 a3275116 + * + * The following value is the updated XKEY value from step 3.2.c: + * + * + * XKEY= 19df679b 881b3991 6875fea0 6b3f8191 19a78fe2 + * + * Step 3.3 provides the following values: + * + * w[0] || w[1]= 2070b322 3dba372f de1c0ffc 7b2e3b49 8b260614 + * 3c6c18ba cb0f6c55 babb1378 8e20d737 a3275116 + * + */ + +#ifdef TEST_CASE + +#include <assert.h> + +uint8_t mk[20]={ 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b, + 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f, + 0xeb, 0x5a, 0x38, 0xb6 }; + +main(int argc, char *argv[]) +{ + uint8_t finalkey[160]; + int i, j, k; + + fips186_2prf(mk, finalkey); + + printf("Input was: |"); + j=0; + for (i = 0; i < 20; i++) { + if(j==4) { + printf("_"); + j=0; + } + j++; + + printf("%02x", mk[i]); + } + + printf("|\nOutput was: "); + j=0; k=0; + for (i = 0; i < 160; i++) { + if(k==20) { + printf("\n "); + k=0; + j=0; + } + if(j==4) { + printf("_"); + j=0; + } + k++; + j++; + + printf("%02x", finalkey[i]); + } + printf("\n"); +} +#endif diff --git a/src/modules/rlm_eap/libeap/mppe_keys.c b/src/modules/rlm_eap/libeap/mppe_keys.c new file mode 100644 index 0000000..385441c --- /dev/null +++ b/src/modules/rlm_eap/libeap/mppe_keys.c @@ -0,0 +1,384 @@ +/* + * mppe_keys.c + * + * 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 2002 Axis Communications AB + * Copyright 2006 The FreeRADIUS server project + * Authors: Henrik Eriksson <henriken@axis.com> & Lars Viklund <larsv@axis.com> + */ + +RCSID("$Id$") +USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ + +#include "eap_tls.h" +#include <openssl/ssl.h> +#include <openssl/hmac.h> +#include <freeradius-devel/openssl3.h> + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include <openssl/provider.h> +#endif + +/* + * TLS P_hash from RFC 2246/5246 section 5 + */ +static void P_hash(EVP_MD const *evp_md, + unsigned char const *secret, unsigned int secret_len, + unsigned char const *seed, unsigned int seed_len, + unsigned char *out, unsigned int out_len) +{ + HMAC_CTX *ctx_a, *ctx_out; + unsigned char a[EVP_MAX_MD_SIZE]; + unsigned int size = EVP_MAX_MD_SIZE; + unsigned int digest_len; + + ctx_a = HMAC_CTX_new(); + ctx_out = HMAC_CTX_new(); + HMAC_Init_ex(ctx_a, secret, secret_len, evp_md, NULL); + HMAC_Init_ex(ctx_out, secret, secret_len, evp_md, NULL); + + /* Calculate A(1) */ + HMAC_Update(ctx_a, seed, seed_len); + HMAC_Final(ctx_a, a, &size); + + while (1) { + /* Calculate next part of output */ + HMAC_Update(ctx_out, a, size); + HMAC_Update(ctx_out, seed, seed_len); + + /* Check if last part */ + if (out_len < size) { + digest_len = EVP_MAX_MD_SIZE; + HMAC_Final(ctx_out, a, &digest_len); + memcpy(out, a, out_len); + break; + } + + /* Place digest in output buffer */ + digest_len = EVP_MAX_MD_SIZE; + HMAC_Final(ctx_out, out, &digest_len); + HMAC_Init_ex(ctx_out, NULL, 0, NULL, NULL); + out += size; + out_len -= size; + + /* Calculate next A(i) */ + HMAC_Init_ex(ctx_a, NULL, 0, NULL, NULL); + HMAC_Update(ctx_a, a, size); + digest_len = EVP_MAX_MD_SIZE; + HMAC_Final(ctx_a, a, &digest_len); + } + + HMAC_CTX_free(ctx_a); + HMAC_CTX_free(ctx_out); + memset(a, 0, sizeof(a)); +} + +/* + * TLS PRF from RFC 2246 section 5 + */ +static void PRF(unsigned char const *secret, unsigned int secret_len, + unsigned char const *seed, unsigned int seed_len, + unsigned char *out, unsigned int out_len) +{ + uint8_t buf[out_len + (out_len % SHA_DIGEST_LENGTH)]; + unsigned int i; + + unsigned int len = (secret_len + 1) / 2; + uint8_t const *s1 = secret; + uint8_t const *s2 = secret + (secret_len - len); + + EVP_MD const *md5 = NULL; + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MD *md5_to_free = NULL; + + /* + * If we are using OpenSSL >= 3.0 and FIPS mode is + * enabled, we need to load the default provider in a + * standalone context in order to access MD5. + */ + OSSL_LIB_CTX *libctx = NULL; + OSSL_PROVIDER *default_provider = NULL; + + if (EVP_default_properties_is_fips_enabled(NULL)) { + libctx = OSSL_LIB_CTX_new(); + default_provider = OSSL_PROVIDER_load(libctx, "default"); + + if (!default_provider) { + ERROR("Failed loading OpenSSL default provider."); + return; + } + + md5_to_free = EVP_MD_fetch(libctx, "MD5", NULL); + if (!md5_to_free) { + ERROR("Failed loading OpenSSL MD5 function."); + return; + } + + md5 = md5_to_free; + } else { + md5 = EVP_md5(); + } +#else + md5 = EVP_md5(); +#endif + + P_hash(md5, s1, len, seed, seed_len, out, out_len); + P_hash(EVP_sha1(), s2, len, seed, seed_len, buf, out_len); + + for (i = 0; i < out_len; i++) { + out[i] ^= buf[i]; + } + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (libctx) { + OSSL_PROVIDER_unload(default_provider); + OSSL_LIB_CTX_free(libctx); + EVP_MD_free(md5_to_free); + } +#endif +} + +/* + * TLS 1.2 PRF from RFC 5246 section 5 + */ +static void PRFv12(unsigned char const *secret, unsigned int secret_len, + unsigned char const *seed, unsigned int seed_len, + unsigned char *out, unsigned int out_len) +{ + P_hash(EVP_sha256(), secret, secret_len, seed, seed_len, out, out_len); +} + +/* 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); +} + +#define EAPTLS_MPPE_KEY_LEN 32 + +/* + * Generate keys according to RFC 2716 and add to reply + */ +void eaptls_gen_mppe_keys(REQUEST *request, SSL *s, char const *label, uint8_t const *context, UNUSED size_t context_size) +{ + uint8_t out[4 * EAPTLS_MPPE_KEY_LEN]; + uint8_t *p; + size_t len; + + len = strlen(label); + +#if OPENSSL_VERSION_NUMBER >= 0x10001000L + if (SSL_export_keying_material(s, out, sizeof(out), label, len, context, context_size, context != NULL) != 1) { + ERROR("Failed generating keying material"); + return; + } +#else + { + uint8_t seed[64 + (2 * SSL3_RANDOM_SIZE) + (context ? 2 + context_size : 0)]; + uint8_t buf[4 * EAPTLS_MPPE_KEY_LEN]; + + p = seed; + + memcpy(p, label, len); + p += len; + + memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); + p += SSL3_RANDOM_SIZE; + len += SSL3_RANDOM_SIZE; + + memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE); + p += SSL3_RANDOM_SIZE; + len += SSL3_RANDOM_SIZE; + + if (context) { + /* cloned and reversed FR_PUT_LE16 */ + p[0] = ((uint16_t) (context_size)) >> 8; + p[1] = ((uint16_t) (context_size)) & 0xff; + p += 2; + len += 2; + memcpy(p, context, context_size); + p += context_size; + len += context_size; + } + + PRF(s->session->master_key, s->session->master_key_length, + seed, len, out, buf, sizeof(out)); + } +#endif + + p = out; + eap_add_reply(request, "MS-MPPE-Recv-Key", p, EAPTLS_MPPE_KEY_LEN); + p += EAPTLS_MPPE_KEY_LEN; + eap_add_reply(request, "MS-MPPE-Send-Key", p, EAPTLS_MPPE_KEY_LEN); + + eap_add_reply(request, "EAP-MSK", out, 64); + eap_add_reply(request, "EAP-EMSK", out + 64, 64); +} + + +#define FR_TLS_PRF_CHALLENGE "ttls challenge" + +/* + * Generate the TTLS challenge + * + * It's in the TLS module simply because it's only a few lines + * of code, and it needs access to the TLS PRF functions. + */ +void eapttls_gen_challenge(SSL *s, uint8_t *buffer, size_t size) +{ +#if OPENSSL_VERSION_NUMBER >= 0x10001000L + if (SSL_export_keying_material(s, buffer, size, FR_TLS_PRF_CHALLENGE, + sizeof(FR_TLS_PRF_CHALLENGE)-1, NULL, 0, 0) != 1) { + ERROR("Failed generating keying material"); + } +#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); + p += SSL3_RANDOM_SIZE; + memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE); + + PRF(s->session->master_key, s->session->master_key_length, + seed, sizeof(seed), out, buf, sizeof(out)); + memcpy(buffer, out, size); +#endif +} + +#define FR_TLS_EXPORTER_METHOD_ID "EXPORTER_EAP_TLS_Method-Id" + +/* + * Actually generates EAP-Session-Id, which is an internal server + * attribute. Not all systems want to send EAP-Key-Name. + */ +void eaptls_gen_eap_key(eap_handler_t *handler) +{ + RADIUS_PACKET *packet = handler->request->reply; + tls_session_t *tls_session = handler->opaque; + SSL *s = tls_session->ssl; + VALUE_PAIR *vp; + uint8_t *buff, *p; + uint8_t type = handler->type & 0xff; + + vp = fr_pair_afrom_num(packet, PW_EAP_SESSION_ID, 0); + if (!vp) return; + + vp->vp_length = 1 + 2 * SSL3_RANDOM_SIZE; + buff = p = talloc_array(vp, uint8_t, vp->vp_length); + + *p++ = type; + + switch (SSL_version(tls_session->ssl)) { + case TLS1_VERSION: + case TLS1_1_VERSION: + case TLS1_2_VERSION: + SSL_get_client_random(s, p, SSL3_RANDOM_SIZE); + p += SSL3_RANDOM_SIZE; + SSL_get_server_random(s, p, SSL3_RANDOM_SIZE); + break; +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#ifdef TLS1_3_VERSION + case TLS1_3_VERSION: +#endif + default: + { + uint8_t const context[] = { type }; + + if (SSL_export_keying_material(s, p, 2 * SSL3_RANDOM_SIZE, + FR_TLS_EXPORTER_METHOD_ID, sizeof(FR_TLS_EXPORTER_METHOD_ID)-1, + context, sizeof(context), 1) != 1) { + ERROR("Failed generating keying material"); + return; + } + } +#endif + } + + vp->vp_octets = buff; + 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, int version, uint8_t *buffer, size_t size, char const *prf_label) +{ + uint8_t *p; + size_t len, master_key_len; + uint8_t seed[128 + 2*SSL3_RANDOM_SIZE]; + uint8_t master_key[SSL_MAX_MASTER_KEY_LENGTH]; + + len = strlen(prf_label); + if (len > 128) len = 128; + + p = seed; + memcpy(p, prf_label, len); + p += len; + SSL_get_server_random(s, p, SSL3_RANDOM_SIZE); + p += SSL3_RANDOM_SIZE; + SSL_get_client_random(s, p, SSL3_RANDOM_SIZE); + p += SSL3_RANDOM_SIZE; + + master_key_len = SSL_SESSION_get_master_key(SSL_get_session(s), master_key, sizeof(master_key)); + + if (version == TLS1_2_VERSION) + PRFv12(master_key, master_key_len, seed, p - seed, buffer, size); + else + PRF(master_key, master_key_len, seed, p - seed, buffer, size); +} diff --git a/src/modules/rlm_eap/mem.c b/src/modules/rlm_eap/mem.c new file mode 100644 index 0000000..6be8ca4 --- /dev/null +++ b/src/modules/rlm_eap/mem.c @@ -0,0 +1,503 @@ +/* + * mem.c Memory allocation, deallocation stuff. + * + * 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 2000,2001,2006 The FreeRADIUS server project + * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com> + */ + +RCSID("$Id$") + +#include <stdio.h> +#include "rlm_eap.h" + +#ifdef WITH_TLS +#include <freeradius-devel/tls.h> +#endif + +#ifdef HAVE_PTHREAD_H +#define PTHREAD_MUTEX_LOCK pthread_mutex_lock +#define PTHREAD_MUTEX_UNLOCK pthread_mutex_unlock +#else +#define PTHREAD_MUTEX_LOCK(_x) +#define PTHREAD_MUTEX_UNLOCK(_x) +#endif + +/* + * Allocate a new eap_packet_t + */ +EAP_DS *eap_ds_alloc(eap_handler_t *handler) +{ + EAP_DS *eap_ds; + + eap_ds = talloc_zero(handler, EAP_DS); + eap_ds->response = talloc_zero(eap_ds, eap_packet_t); + if (!eap_ds->response) { + eap_ds_free(&eap_ds); + return NULL; + } + eap_ds->request = talloc_zero(eap_ds, eap_packet_t); + if (!eap_ds->response) { + eap_ds_free(&eap_ds); + return NULL; + } + + return eap_ds; +} + +void eap_ds_free(EAP_DS **eap_ds_p) +{ + EAP_DS *eap_ds; + + if (!eap_ds_p) return; + + eap_ds = *eap_ds_p; + if (!eap_ds) return; + + if (eap_ds->response) talloc_free(eap_ds->response); + if (eap_ds->request) talloc_free(eap_ds->request); + + talloc_free(eap_ds); + *eap_ds_p = NULL; +} + +static int _eap_handler_free(eap_handler_t *handler) +{ + if (handler->identity) { + talloc_free(handler->identity); + handler->identity = NULL; + } + + if (handler->prev_eapds) eap_ds_free(&(handler->prev_eapds)); + if (handler->eap_ds) eap_ds_free(&(handler->eap_ds)); + + if ((handler->opaque) && (handler->free_opaque)) { + handler->free_opaque(handler->opaque); + handler->opaque = NULL; + } + + handler->opaque = NULL; + handler->free_opaque = NULL; + + /* + * Give helpful debug messages if: + * + * we're debugging TLS sessions, which don't finish, + * and which aren't deleted early due to a likely RADIUS + * retransmit which nukes our ID, and therefore our stare. + */ + if (fr_debug_lvl && handler->tls && !handler->finished && + (time(NULL) > (handler->timestamp + 3))) { + WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + WARN("!! EAP session with state 0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x did not finish! !!", + handler->state[0], handler->state[1], + handler->state[2], handler->state[3], + handler->state[4], handler->state[5], + handler->state[6], handler->state[7], + handler->state[8], handler->state[9], + handler->state[10], handler->state[11], + handler->state[12], handler->state[13], + handler->state[14], handler->state[15]); + + WARN("!! Please read http://wiki.freeradius.org/guide/Certificate_Compatibility !!"); + WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + } + + return 0; +} + +/* + * Allocate a new eap_handler_t + */ +eap_handler_t *eap_handler_alloc(rlm_eap_t *inst) +{ + eap_handler_t *handler; + + handler = talloc_zero(NULL, eap_handler_t); + if (!handler) { + ERROR("Failed allocating handler"); + return NULL; + } + handler->inst_holder = inst; + + /* Doesn't need to be inside the critical region */ + talloc_set_destructor(handler, _eap_handler_free); + + return handler; +} + + +void eaplist_free(rlm_eap_t *inst) +{ + eap_handler_t *node, *next; + + for (node = inst->session_head; node != NULL; node = next) { + next = node->next; + talloc_free(node); + } + + inst->session_head = inst->session_tail = NULL; +} + +/* + * Return a 32-bit random number. + */ +static uint32_t eap_rand(fr_randctx *ctx) +{ + uint32_t num; + + num = ctx->randrsl[ctx->randcnt++]; + if (ctx->randcnt >= 256) { + ctx->randcnt = 0; + fr_isaac(ctx); + } + + return num; +} + + +static eap_handler_t *eaplist_delete(rlm_eap_t *inst, REQUEST *request, + eap_handler_t *handler) +{ + rbnode_t *node; + + node = rbtree_find(inst->session_tree, handler); + if (!node) return NULL; + + handler = rbtree_node2data(inst->session_tree, node); + + RDEBUG("Finished EAP session with state " + "0x%02x%02x%02x%02x%02x%02x%02x%02x", + handler->state[0], handler->state[1], + handler->state[2], handler->state[3], + handler->state[4], handler->state[5], + handler->state[6], handler->state[7]); + /* + * Delete old handler from the tree. + */ + rbtree_delete(inst->session_tree, node); + + /* + * And unsplice it from the linked list. + */ + if (handler->prev) { + handler->prev->next = handler->next; + } else { + inst->session_head = handler->next; + } + if (handler->next) { + handler->next->prev = handler->prev; + } else { + inst->session_tail = handler->prev; + } + handler->prev = handler->next = NULL; + + return handler; +} + + +static void eaplist_expire(rlm_eap_t *inst, REQUEST *request, time_t timestamp) +{ + int i; + eap_handler_t *handler; + + /* + * Check the first few handlers in the list, and delete + * them if they're too old. We don't need to check them + * all, as incoming requests will quickly cause older + * handlers to be deleted. + * + */ + for (i = 0; i < 3; i++) { + handler = inst->session_head; + if (!handler) break; + + RDEBUG("Expiring EAP session with state " + "0x%02x%02x%02x%02x%02x%02x%02x%02x", + handler->state[0], handler->state[1], + handler->state[2], handler->state[3], + handler->state[4], handler->state[5], + handler->state[6], handler->state[7]); + + /* + * Expire entries from the start of the list. + * They should be the oldest ones. + */ + if ((timestamp - handler->timestamp) > (int)inst->timer_limit) { + rbnode_t *node; + node = rbtree_find(inst->session_tree, handler); + rad_assert(node != NULL); + rbtree_delete(inst->session_tree, node); + + /* + * handler == inst->session_head + */ + inst->session_head = handler->next; + if (handler->next) { + handler->next->prev = NULL; + } else { + inst->session_head = NULL; + inst->session_tail = NULL; + } + +#ifdef WITH_TLS + /* + * Remove expired TLS sessions. + */ + switch (handler->type) { + case PW_EAP_TLS: + case PW_EAP_TTLS: + case PW_EAP_PEAP: + case PW_EAP_FAST: + tls_fail(handler->opaque); /* MUST be a tls_session! */ + break; + + default: + break; + } +#endif + + talloc_free(handler); + } else { + break; + } + } +} + +/* + * Add a handler to the set of active sessions. + * + * Since we're adding it to the list, we guess that this means + * the packet needs a State attribute. So add one. + */ +int eaplist_add(rlm_eap_t *inst, eap_handler_t *handler) +{ + int status = 0; + VALUE_PAIR *state; + REQUEST *request = handler->request; + + /* + * Generate State, since we've been asked to add it to + * the list. + */ + state = pair_make_reply("State", NULL, T_OP_EQ); + if (!state) return 0; + + /* + * The time at which this request was made was the time + * at which it was received by the RADIUS server. + */ + handler->timestamp = request->timestamp; + handler->status = 1; + + handler->src_ipaddr = request->packet->src_ipaddr; + handler->eap_id = handler->eap_ds->request->id; + + /* + * Playing with a data structure shared among threads + * means that we need a lock, to avoid conflict. + */ + PTHREAD_MUTEX_LOCK(&(inst->session_mutex)); + + /* + * If we have a DoS attack, discard new sessions. + */ + if (rbtree_num_elements(inst->session_tree) >= inst->max_sessions) { + status = -1; + eaplist_expire(inst, request, handler->timestamp); + goto done; + } + + /* + * Create a unique content for the State variable. + * It will be modified slightly per round trip, but less so + * than in 1.x. + */ + if (handler->trips == 0) { + int i; + + for (i = 0; i < 4; i++) { + uint32_t lvalue; + + lvalue = eap_rand(&inst->rand_pool); + + memcpy(handler->state + i * 4, &lvalue, + sizeof(lvalue)); + } + } + + /* + * Add some more data to distinguish the sessions. + */ + handler->state[4] = handler->trips ^ handler->state[0]; + handler->state[5] = handler->eap_id ^ handler->state[1]; + handler->state[6] = handler->type ^ handler->state[2]; + handler->state[12] = handler->state[2] ^ (RADIUSD_VERSION & 0xff); + + fr_pair_value_memcpy(state, handler->state, sizeof(handler->state)); + + /* + * Big-time failure. + */ + status = rbtree_insert(inst->session_tree, handler); + + if (status) { + eap_handler_t *prev; + + prev = inst->session_tail; + if (prev) { + prev->next = handler; + handler->prev = prev; + handler->next = NULL; + inst->session_tail = handler; + } else { + inst->session_head = inst->session_tail = handler; + handler->next = handler->prev = NULL; + } + } + + /* + * Now that we've finished mucking with the list, + * unlock it. + */ + done: + + /* + * We don't need this any more. + */ + if (status > 0) handler->request = NULL; + + PTHREAD_MUTEX_UNLOCK(&(inst->session_mutex)); + + if (status <= 0) { + fr_pair_delete_by_num(&request->reply->vps, PW_STATE, 0, TAG_ANY); + + if (status < 0) { + static time_t last_logged = 0; + + if (last_logged < handler->timestamp) { + last_logged = handler->timestamp; + ERROR("rlm_eap (%s): Too many open sessions. Try increasing \"max_sessions\" " + "in the EAP module configuration", inst->xlat_name); + } + } else { + ERROR("rlm_eap (%s): Failed to store handler", inst->xlat_name); + } + return 0; + } + + RDEBUG("EAP session adding &reply:State = 0x%02x%02x%02x%02x%02x%02x%02x%02x", + state->vp_octets[0], state->vp_octets[1], state->vp_octets[2], state->vp_octets[3], + state->vp_octets[4], state->vp_octets[5], state->vp_octets[6], state->vp_octets[7]); + + return 1; +} + +/* + * Find a a previous EAP-Request sent by us, which matches + * the current EAP-Response. + * + * Then, release the handle from the list, and return it to + * the caller. + * + * Also since we fill the eap_ds with the present EAP-Response we + * got to free the prev_eapds & move the eap_ds to prev_eapds + */ +eap_handler_t *eaplist_find(rlm_eap_t *inst, REQUEST *request, + eap_packet_raw_t *eap_packet) +{ + VALUE_PAIR *state; + eap_handler_t *handler, myHandler; + + /* + * We key the sessions off of the 'state' attribute, so it + * must exist. + */ + state = fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY); + 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; + } + + myHandler.src_ipaddr = request->packet->src_ipaddr; + myHandler.eap_id = eap_packet->id; + memcpy(myHandler.state, state->vp_strvalue, sizeof(myHandler.state)); + + /* + * Playing with a data structure shared among threads + * means that we need a lock, to avoid conflict. + */ + PTHREAD_MUTEX_LOCK(&(inst->session_mutex)); + + eaplist_expire(inst, request, request->timestamp); + + handler = eaplist_delete(inst, request, &myHandler); + PTHREAD_MUTEX_UNLOCK(&(inst->session_mutex)); + + /* + * Might not have been there. + */ + if (!handler) { + RERROR("rlm_eap (%s): No EAP session matching state " + "0x%02x%02x%02x%02x%02x%02x%02x%02x", + inst->xlat_name, + state->vp_octets[0], state->vp_octets[1], + state->vp_octets[2], state->vp_octets[3], + state->vp_octets[4], state->vp_octets[5], + state->vp_octets[6], state->vp_octets[7]); + return NULL; + } + + if (handler->trips >= 50) { + RERROR("rlm_eap (%s): Aborting! More than 50 roundtrips " + "made in session with state " + "0x%02x%02x%02x%02x%02x%02x%02x%02x", + inst->xlat_name, + state->vp_octets[0], state->vp_octets[1], + state->vp_octets[2], state->vp_octets[3], + state->vp_octets[4], state->vp_octets[5], + state->vp_octets[6], state->vp_octets[7]); + + + talloc_free(handler); + return NULL; + } + handler->trips++; + + RDEBUG("Previous EAP request found for state " + "0x%02x%02x%02x%02x%02x%02x%02x%02x, released from the list", + state->vp_octets[0], state->vp_octets[1], + state->vp_octets[2], state->vp_octets[3], + state->vp_octets[4], state->vp_octets[5], + state->vp_octets[6], state->vp_octets[7]); + + /* + * Remember what the previous request was. + */ + eap_ds_free(&(handler->prev_eapds)); + handler->prev_eapds = handler->eap_ds; + handler->eap_ds = NULL; + + return handler; +} diff --git a/src/modules/rlm_eap/radeapclient.c b/src/modules/rlm_eap/radeapclient.c new file mode 100644 index 0000000..cd504a8 --- /dev/null +++ b/src/modules/rlm_eap/radeapclient.c @@ -0,0 +1,2306 @@ +/* + * radeapclient.c EAP specific radius packet debug tool. + * + * 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 2000,2006 The FreeRADIUS server project + * Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl> + * Copyright 2000 Alan DeKok <aland@ox.org> + */ + +RCSID("$Id$") + +#include <freeradius-devel/libradius.h> + +#include <ctype.h> +#include <assert.h> + +#if HAVE_GETOPT_H +# include <getopt.h> +#endif + +#include <freeradius-devel/conf.h> +#include <freeradius-devel/radpaths.h> +#include <freeradius-devel/md5.h> + +#include "eap_types.h" +#include "eap_sim.h" +#include "comp128.h" + +extern int sha1_data_problems; + +#undef DEBUG +#undef DEBUG2 +#undef ERROR + +#define DEBUG if (fr_debug_lvl && fr_log_fp) fr_printf_log +#define DEBUG2 if ((fr_debug_lvl >= 2) && fr_log_fp) fr_printf_log +#define ERROR if (fr_debug_lvl && fr_log_fp) fr_printf_log + +#define USEC 1000000 + +static uint32_t parallel = 1; +static unsigned int retries = 3; +static float timeout = 5; +static struct timeval tv_timeout; +static char const *secret = NULL; +static int do_output = 1; +static int do_summary = 0; +static int totalapp = 0; +static int totaldeny = 0; +static char filesecret[256]; +static char const *radius_dir = NULL; +static char const *progname = "radeapclient"; +/* fr_randctx randctx; */ + +main_config_t main_config; +char const *radiusd_version = ""; + +#ifdef WITH_TLS +#include <freeradius-devel/tls.h> +#endif + +log_lvl_t rad_debug_lvl = 0; + +//TODO: move structures to a header file. + +typedef struct rc_input_vps_list rc_input_vps_list_t; +typedef struct rc_input_vps rc_input_vps_t; +typedef struct rc_transaction rc_transaction_t; + +/** Structure which contains EAP context, necessary to perform the full EAP transaction. + */ +typedef struct rc_eap_sim_context { + struct eapsim_keys keys; +} rc_eap_sim_context_t; + +typedef struct rc_eap_md5_context { + int tried; +} rc_eap_md5_context_t; + +typedef struct rc_eap_context { + int eap_type; //!< contains the EAP-Type + char password[256]; //!< copy of User-Password (or CHAP-Password). + VALUE_PAIR *ki; + union { + rc_eap_sim_context_t sim; + rc_eap_md5_context_t md5; + } eap; +} rc_eap_context_t; + + +/** Structure which holds a list of available input vps. + */ +struct rc_input_vps_list { + rc_input_vps_t *head; + rc_input_vps_t *tail; + uint32_t size; +}; + +/** Structure which holds an input vps entry (read from file or stdin), + * and linkage to previous / next entries. + */ +struct rc_input_vps { + uint32_t num; //!< The number (within the file) of the input we're reading. + + VALUE_PAIR *vps_in; //!< the list of attribute/value pairs. + + rc_input_vps_list_t *list; //!< the list to which this entry belongs (NULL for an unchained entry). + + rc_input_vps_t *prev; + rc_input_vps_t *next; +}; + + +/** Structure which holds a transaction: sent packet, reply received... + */ +struct rc_transaction { + uint32_t id; //!< id of transaction (0 for the first one). + + uint32_t num_packet; //!< number of packets sent for this transaction. + + RADIUS_PACKET *packet; + RADIUS_PACKET *reply; + + rc_input_vps_t *input_vps; + + rc_eap_context_t *eap_context; + + uint32_t tries; + + fr_event_t *event; //!< armed event (if any). + + char password[256]; + char const *name; //!< Test name (as specified in the request). +}; + +typedef struct eap_sim_server_state { + enum eapsim_serverstates state; + struct eapsim_keys keys; + int sim_id; +} eap_sim_state_t; + + +static TALLOC_CTX *autofree; +static uint32_t num_trans = 0; //!< number of transactions initialized. +static uint32_t num_started = 0; //!< number of transactions started. +static uint32_t num_ongoing = 0; //!< number of ongoing transactions. +static uint32_t num_finished = 0; //!< number of finished transactions. + +static rc_input_vps_list_t rc_vps_list_in; //!< list of available input vps entries. +static fr_packet_list_t *pl = NULL; //!< list of outgoing packets. +static unsigned int num_sockets = 0; //!< number of allocated sockets. +static fr_event_list_t *ev_list = NULL; //!< list of armed events. + +static int force_af = AF_UNSPEC; +static int ipproto = IPPROTO_UDP; +static fr_ipaddr_t server_ipaddr; +static bool server_addr_init = false; +static uint16_t server_port = 0; +static int packet_code = PW_CODE_UNDEFINED; + +static int rc_map_eap_methods(RADIUS_PACKET *req); +static void rc_unmap_eap_methods(RADIUS_PACKET *rep); +static int rc_map_eapsim_types(RADIUS_PACKET *r); +static int rc_unmap_eapsim_types(RADIUS_PACKET *r); + +static void rc_get_port(PW_CODE type, uint16_t *port); +static void rc_evprep_packet_timeout(rc_transaction_t *trans); +static void rc_deallocate_id(rc_transaction_t *trans); + +/* + * For cbtls_cache_*() + */ +rlm_rcode_t process_post_auth(UNUSED int postauth_type, UNUSED REQUEST *request) +{ + return RLM_MODULE_FAIL; +} + + +static void NEVER_RETURNS usage(void) +{ + fprintf(stdout, "Usage: radeapclient [options] server[:port] <command> [<secret>]\n"); + + fprintf(stdout, " <command> One of auth, acct, status, coa, disconnect or auto.\n"); + fprintf(stdout, " -4 Use IPv4 address of server\n"); + fprintf(stdout, " -6 Use IPv6 address of server.\n"); + fprintf(stdout, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n"); + fprintf(stdout, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n"); + fprintf(stdout, " -f <file> Read packets from file, not stdin.\n"); + fprintf(stdout, " -h Print usage help information.\n"); + fprintf(stdout, " -p <num> Send 'num' packets in parallel.\n"); + fprintf(stdout, " -q Do not print anything out.\n"); + fprintf(stdout, " -r <retries> If timeout, retry sending the packet 'retries' times.\n"); + fprintf(stdout, " -s Print out summary information of auth results.\n"); + fprintf(stdout, " -S <file> read secret from file, not command line.\n"); + fprintf(stdout, " -t <timeout> Wait 'timeout' seconds before retrying (may be a floating point number).\n"); + fprintf(stdout, " -v Show program version information.\n"); + fprintf(stdout, " -x Debugging mode.\n"); + + exit(1); +} + +static const FR_NAME_NUMBER rc_request_types[] = { + { "auth", PW_CODE_ACCESS_REQUEST }, + { "challenge", PW_CODE_ACCESS_CHALLENGE }, + { "acct", PW_CODE_ACCOUNTING_REQUEST }, + { "status", PW_CODE_STATUS_SERVER }, + { "disconnect", PW_CODE_DISCONNECT_REQUEST }, + { "coa", PW_CODE_COA_REQUEST }, + { "auto", PW_CODE_UNDEFINED }, + + { NULL, 0} +}; + +int rad_virtual_server(REQUEST UNUSED *request) +{ + /*We're not the server so we cannot do this*/ + abort(); +} + +/** Convert a float to struct timeval. + */ +static void rc_float_to_timeval(struct timeval *tv, float f_val) +{ + tv->tv_sec = (time_t)f_val; + uint64_t usec = (uint64_t)(f_val * USEC) - (tv->tv_sec * USEC); + tv->tv_usec = usec; +} + +/** Add an allocated rc_input_vps_t entry to the tail of the list. + */ + static void rc_add_vps_entry(rc_input_vps_list_t *list, rc_input_vps_t *entry) +{ + if (!list || !entry) return; + + if (!list->head) { + assert(list->tail == NULL); + list->head = entry; + entry->prev = NULL; + } else { + assert(list->tail != NULL); + assert(list->tail->next == NULL); + list->tail->next = entry; + entry->prev = list->tail; + } + list->tail = entry; + entry->next = NULL; + entry->list = list; + list->size ++; +} + +/** Remove a selected rc_input_vps_t entry from its current list. + */ +static rc_input_vps_t *rc_yank_vps_entry(rc_input_vps_t *entry) +{ + if (!entry) return NULL; + + if (!entry->list) return entry; /* not in a list, nothing to do. Just return the entry. */ + + rc_input_vps_t *prev, *next; + + prev = entry->prev; + next = entry->next; + + rc_input_vps_list_t *list = entry->list; + + assert(list->head != NULL); /* entry belongs to a list, so the list can't be empty. */ + assert(list->tail != NULL); /* same. */ + + if (prev) { + assert(list->head != entry); /* if entry has a prev, then entry can't be head. */ + prev->next = next; + } + else { + assert(list->head == entry); /* if entry has no prev, then entry must be head. */ + list->head = next; + } + + if (next) { + assert(list->tail != entry); /* if entry has a next, then entry can't be tail. */ + next->prev = prev; + } + else { + assert(list->tail == entry); /* if entry has no next, then entry must be tail. */ + list->tail = prev; + } + + entry->list = NULL; + entry->prev = NULL; + entry->next = NULL; + list->size --; + return entry; +} + +/** Load input entries (list of vps) from a file or stdin, and add them to the list. + * They will be used to initiate transactions. + */ +static int rc_load_input(TALLOC_CTX *ctx, char const *filename, rc_input_vps_list_t *list, uint32_t max_entries) +{ + FILE *file_in = NULL; + bool file_done = false; + rc_input_vps_t *request; + char const *input; + uint32_t input_num = 0; + + /* Determine where to read the VP's from. */ + if (filename && strcmp(filename, "-") != 0) { + DEBUG2("Opening input file: %s\n", filename); + file_in = fopen(filename, "r"); + if (!file_in) { + ERROR("Error opening %s: %s\n", filename, strerror(errno)); + return 0; + } + input = filename; + } else { + DEBUG2("Reading input vps from stdin\n"); + file_in = stdin; + input = "stdin"; + } + + /* Loop over the file (or stdin). */ + do { + input_num ++; + MEM(request = talloc_zero(ctx, rc_input_vps_t)); + + if (fr_pair_list_afrom_file(request, &request->vps_in, file_in, &file_done) < 0) { + ERROR("Error parsing entry %u from input: %s\n", input_num, input); + talloc_free(request); + break; + } + if (NULL == request->vps_in) { + /* Last line might be empty, in this case fr_pair_list_afrom_file will return a NULL vps pointer. Silently ignore this. */ + talloc_free(request); + break; + } + + /* Add that to the list */ + rc_add_vps_entry(list, request); + + request->num = list->size; + + if (max_entries && list->size >= max_entries) { + /* Only load what we need. */ + break; + } + } while (!file_done); + + if (file_in != stdin) fclose(file_in); + + /* And we're done. */ + DEBUG("Read %d element(s) from input: %s\n", list->size, input); + return 1; +} + +/** Perform packet initialization for a transaction. + */ +static int rc_init_packet(rc_transaction_t *trans) +{ + if (!trans || !trans->packet) return 0; + + RADIUS_PACKET *packet = trans->packet; + vp_cursor_t cursor; + VALUE_PAIR *vp; + + /* + * Process special attributes + */ + for (vp = fr_cursor_init(&cursor, &packet->vps); + vp; + vp = fr_cursor_next(&cursor)) { + /* + * Double quoted strings get marked up as xlat expansions, + * but we don't support that in request. + */ + if (vp->type == VT_XLAT) { + vp->type = VT_DATA; + vp->vp_strvalue = vp->value.xlat; + vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1; + } + + if (!vp->da->vendor) switch (vp->da->attr) { + default: + break; + + /* + * Allow it to set the packet type in + * the attributes read from the file. + */ + case PW_PACKET_TYPE: + packet->code = vp->vp_integer; + break; + + case PW_PACKET_DST_PORT: + packet->dst_port = (vp->vp_integer & 0xffff); + break; + + case PW_PACKET_DST_IP_ADDRESS: + packet->dst_ipaddr.af = AF_INET; + packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; + packet->dst_ipaddr.prefix = 32; + break; + + case PW_PACKET_DST_IPV6_ADDRESS: + packet->dst_ipaddr.af = AF_INET6; + packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; + packet->dst_ipaddr.prefix = 128; + break; + + case PW_PACKET_SRC_PORT: + if ((vp->vp_integer < 1024) || + (vp->vp_integer > 65535)) { + DEBUG("Invalid value '%u' for Packet-Src-Port\n", vp->vp_integer); + } else { + packet->src_port = (vp->vp_integer & 0xffff); + } + break; + + case PW_PACKET_SRC_IP_ADDRESS: + packet->src_ipaddr.af = AF_INET; + packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; + packet->src_ipaddr.prefix = 32; + break; + + case PW_PACKET_SRC_IPV6_ADDRESS: + packet->src_ipaddr.af = AF_INET6; + packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; + packet->src_ipaddr.prefix = 128; + break; + + case PW_DIGEST_REALM: + case PW_DIGEST_NONCE: + case PW_DIGEST_METHOD: + case PW_DIGEST_URI: + case PW_DIGEST_QOP: + case PW_DIGEST_ALGORITHM: + case PW_DIGEST_BODY_DIGEST: + case PW_DIGEST_CNONCE: + case PW_DIGEST_NONCE_COUNT: + case PW_DIGEST_USER_NAME: + /* overlapping! */ + { + DICT_ATTR const *da; + uint8_t *p, *q; + + p = talloc_array(vp, uint8_t, vp->vp_length + 2); + + memcpy(p + 2, vp->vp_octets, vp->vp_length); + p[0] = vp->da->attr - PW_DIGEST_REALM + 1; + vp->vp_length += 2; + p[1] = vp->vp_length; + + da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0); + if (!da) { + ERROR("Attribute 'Digest-Attributes' not found by value\n"); + exit(1); + } + vp->da = da; + + /* + * Re-do fr_pair_value_memsteal ourselves, + * because we play games with + * vp->da, and fr_pair_value_memsteal goes + * to GREAT lengths to sanitize + * and fix and change and + * double-check the various + * fields. + */ + memcpy(&q, &vp->vp_octets, sizeof(q)); + talloc_free(q); + + vp->vp_octets = talloc_steal(vp, p); + vp->type = VT_DATA; + + VERIFY_VP(vp); + } + break; + + /* + * Keep a copy of the the password attribute. + */ + case PW_CLEARTEXT_PASSWORD: + case PW_USER_PASSWORD: + case PW_CHAP_PASSWORD: + case PW_MS_CHAP_PASSWORD: + strlcpy(trans->password, vp->vp_strvalue, sizeof(trans->password)); + break; + + case PW_RADCLIENT_TEST_NAME: + trans->name = vp->vp_strvalue; + break; + } + } /* loop over the VP's we read in */ + + if (packet->dst_port == 0) packet->dst_port = server_port; + + if (packet->dst_ipaddr.af == AF_UNSPEC) { + if (!server_addr_init) { + DEBUG("No server was given, and input entry %u did not contain Packet-Dst-IP-Address, ignored.\n", trans->input_vps->num); + return 0; + } + packet->dst_ipaddr = server_ipaddr; + } + + /* Use the default set on the command line. */ + if (packet->code == PW_CODE_UNDEFINED) { + if (packet_code == PW_CODE_UNDEFINED) { + DEBUG("No packet type was given, and input entry %u did not contain Packet-Type, ignored.\n", trans->input_vps->num); + return 0; + } + packet->code = packet_code; + } + + /* Automatically set the dst port (if one wasn't already set). */ + if (packet->dst_port == 0) { + rc_get_port(packet->code, &packet->dst_port); + if (packet->dst_port == 0) { + DEBUG("Can't determine destination port for input entry %u, ignored.\n", trans->input_vps->num); + return 0; + } + } + + packet->sockfd = -1; + + /* Done. */ + return 1; +} + +/** Map EAP methods and build EAP-Message (if EAP is involved). + * Also allocate the EAP context. + */ +static void rc_build_eap_context(rc_transaction_t *trans) +{ + if (!trans || !trans->packet) return; + + RADIUS_PACKET *packet = trans->packet; + + /* Build EAP-Message (if EAP is involved. Otherwise, do nothing). */ + int eap_type = rc_map_eap_methods(packet); + + if (eap_type) { + if (!trans->eap_context) { + MEM(trans->eap_context = talloc_zero(trans, rc_eap_context_t)); + } + trans->eap_context->eap_type = eap_type; + + /* + * Keep a copy of the the User-Password or CHAP-Password. + * Note: this is not useful for EAP-SIM, but we cannot know what kind + * of challenge the server will issue. + */ + VALUE_PAIR *vp; + vp = fr_pair_find_by_num(packet->vps, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY); + if (!vp) vp = fr_pair_find_by_num(packet->vps, PW_USER_PASSWORD, 0, TAG_ANY); + if (!vp) vp = fr_pair_find_by_num(packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY); + if (vp) { + strlcpy(trans->eap_context->password, vp->vp_strvalue, sizeof(trans->eap_context->password)); + } + + vp = fr_pair_find_by_num(packet->vps, PW_EAP_SIM_KI, 0, TAG_ANY); + if (vp) trans->eap_context->ki = fr_pair_copy(autofree, vp); + } +} + + +/** Grab an element from the input list. Initialize a new transaction context, using this element. + */ +static rc_transaction_t *rc_init_transaction(TALLOC_CTX *ctx) +{ + if (!rc_vps_list_in.head || rc_vps_list_in.size == 0) { + /* Empty list, can't create a new transaction. */ + return NULL; + } + + rc_input_vps_t *vps_entry = rc_vps_list_in.head; + + rc_yank_vps_entry(vps_entry); /* This cannot fail (we checked the list beforehand.) */ + + /* We grabbed an vps entry, now we can initialize a new transaction. */ + rc_transaction_t *trans; + MEM(trans = talloc_zero(ctx, rc_transaction_t)); + + trans->input_vps = vps_entry; + trans->id = num_trans ++; + + talloc_steal(trans, vps_entry); /* It's ours now. */ + + RADIUS_PACKET *packet; + MEM(packet = rad_alloc(trans, 1)); + trans->packet = packet; + + /* Fill in the packet value pairs. */ + packet->vps = fr_pair_list_copy(packet, vps_entry->vps_in); + + /* Initialize the transaction packet. */ + if (!rc_init_packet(trans)) { + /* Failed... */ + talloc_free(trans); + return NULL; + } + + /* Update transactions counters. */ + num_started ++; + num_ongoing ++; + + return trans; +} + +/** Terminate a transaction. + */ +static void rc_finish_transaction(rc_transaction_t *trans) +{ + if (!trans) return; + + if (trans->event) fr_event_delete(ev_list, &trans->event); + rc_deallocate_id(trans); + talloc_free(trans); + + /* Update transactions counters. */ + num_ongoing --; + num_finished ++; + + DEBUG4("pl: %d, ev: %d, in: %d\n", fr_packet_list_num_outgoing(pl), fr_event_list_num_elements(ev_list), rc_vps_list_in.size); +} + + +static uint16_t getport(char const *name) +{ + struct servent *svp; + + svp = getservbyname(name, "udp"); + if (!svp) return 0; + + return ntohs(svp->s_port); +} + + +static void rc_cleanresp(RADIUS_PACKET *resp) +{ + VALUE_PAIR *vpnext, *vp, **last; + + /* + * maybe should just copy things we care about, or keep + * a copy of the original input and start from there again? + */ + fr_pair_delete_by_num(&resp->vps, PW_EAP_MESSAGE, 0, TAG_ANY); + fr_pair_delete_by_num(&resp->vps, PW_EAP_TYPE_BASE+PW_EAP_IDENTITY, 0, TAG_ANY); + + last = &resp->vps; + for (vp = *last; vp != NULL; vp = vpnext) + { + vpnext = vp->next; + + if ((vp->da->attr > PW_EAP_TYPE_BASE && + vp->da->attr <= PW_EAP_TYPE_BASE+256) || + (vp->da->attr > PW_EAP_SIM_BASE && + vp->da->attr <= PW_EAP_SIM_BASE+256)) + { + *last = vpnext; + talloc_free(vp); + } else { + last = &vp->next; + } + } +} + + +static void generate_triplets(RADIUS_PACKET *packet, VALUE_PAIR *ki, uint8_t const *ch) +{ + int i, idx; + eap_sim_state_t ess; + + for (idx = 0; idx < 3; idx++) { + VALUE_PAIR *vp; + char *p; + char buffer[33]; /* 32 hexits (16 bytes) + 1 */ + + for (i = 0; i < EAPSIM_RAND_SIZE; i++) { + ess.keys.rand[idx][i] = ch[(idx * EAPSIM_RAND_SIZE) + i]; + } + + /* + * <sigh>, we always do version 1. + */ + switch (EAP_SIM_VERSION) { + case 1: + comp128v1(ess.keys.sres[idx], ess.keys.Kc[idx], ki->vp_octets, ess.keys.rand[idx]); + break; + + case 2: + comp128v23(ess.keys.sres[idx], ess.keys.Kc[idx], ki->vp_octets, ess.keys.rand[idx], + true); + break; + + case 3: + comp128v23(ess.keys.sres[idx], ess.keys.Kc[idx], ki->vp_octets, ess.keys.rand[idx], + false); + break; + + case 4: + DEBUG("Comp128-4 algorithm is not supported as details have not yet been published. " + "If you have details of this algorithm please contact the FreeRADIUS " + "maintainers\n"); + break; + + default: + DEBUG("Unknown/unsupported algorithm Comp128-4\n"); + } + + + DEBUG2("Generated following triplets for round %i:\n", idx); + + p = buffer; + for (i = 0; i < EAPSIM_RAND_SIZE; i++) { + p += sprintf(p, "%02x", ess.keys.rand[idx][i]); + } + DEBUG2("RAND%d : 0x%s\n", idx, buffer); + vp = fr_pair_afrom_num(packet, PW_EAP_SIM_RAND1 + idx, 0); + fr_pair_value_memcpy(vp, ess.keys.rand[idx], EAPSIM_RAND_SIZE); + fr_pair_add(&packet->vps, vp); + + p = buffer; + for (i = 0; i < EAPSIM_SRES_SIZE; i++) { + p += sprintf(p, "%02x", ess.keys.sres[idx][i]); + } + DEBUG2("SRES%d : 0x%s\n", idx, buffer); + vp = fr_pair_afrom_num(packet, PW_EAP_SIM_SRES1 + idx, 0); + fr_pair_value_memcpy(vp, ess.keys.sres[idx], EAPSIM_SRES_SIZE); + fr_pair_add(&packet->vps, vp); + + p = buffer; + for (i = 0; i < EAPSIM_KC_SIZE; i++) { + p += sprintf(p, "%02x", ess.keys.Kc[idx][i]); + } + DEBUG2("Kc%d : 0x%s\n", idx, buffer); + vp = fr_pair_afrom_num(packet, PW_EAP_SIM_KC1 + idx, 0); + fr_pair_value_memcpy(vp, ess.keys.Kc[idx], EAPSIM_KC_SIZE); + fr_pair_add(&packet->vps, vp); + } +} + + +/* + * we got an EAP-Request/Sim/Start message in a legal state. + * + * pick a supported version, put it into the reply, and insert a nonce. + */ +static int rc_process_eap_start(rc_eap_context_t *eap_context, + RADIUS_PACKET *req, RADIUS_PACKET *rep) +{ + VALUE_PAIR *vp, *newvp; + VALUE_PAIR *anyidreq_vp, *fullauthidreq_vp, *permanentidreq_vp; + uint16_t const *versions; + uint16_t selectedversion; + unsigned int i,versioncount; + VALUE_PAIR *ki; + + /* form new response clear of any EAP stuff */ + rc_cleanresp(rep); + + if ((vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_VERSION_LIST, 0, TAG_ANY)) == NULL) { + ERROR("illegal start message has no VERSION_LIST\n"); + return 0; + } + + versions = (uint16_t const *) vp->vp_strvalue; + + /* verify that the attribute length is big enough for a length field */ + if (vp->vp_length < 4) + { + ERROR("start message has illegal VERSION_LIST. Too short: %u\n", (unsigned int) vp->vp_length); + return 0; + } + + versioncount = ntohs(versions[0])/2; + /* verify that the attribute length is big enough for the given number + * of versions present. + */ + if ((unsigned)vp->vp_length <= (versioncount*2 + 2)) + { + ERROR("start message is too short. Claimed %d versions does not fit in %u bytes\n", versioncount, (unsigned int) vp->vp_length); + return 0; + } + + /* + * record the versionlist for the MK calculation. + */ + eap_context->eap.sim.keys.versionlistlen = versioncount*2; + memcpy(eap_context->eap.sim.keys.versionlist, (unsigned char const *)(versions+1), + eap_context->eap.sim.keys.versionlistlen); + + /* walk the version list, and pick the one we support, which + * at present, is 1, EAP_SIM_VERSION. + */ + selectedversion=0; + for (i=0; i < versioncount; i++) + { + if (ntohs(versions[i+1]) == EAP_SIM_VERSION) + { + selectedversion=EAP_SIM_VERSION; + break; + } + } + if (selectedversion == 0) + { + ERROR("eap-sim start message. No compatible version found. We need %d\n", EAP_SIM_VERSION); + for (i=0; i < versioncount; i++) + { + ERROR("\tfound version %d\n", + ntohs(versions[i+1])); + } + } + + /* + * now make sure that we have only FULLAUTH_ID_REQ. + * I think that it actually might not matter - we can answer in + * anyway we like, but it is illegal to have more than one + * present. + */ + anyidreq_vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_ANY_ID_REQ, 0, TAG_ANY); + fullauthidreq_vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_FULLAUTH_ID_REQ, 0, TAG_ANY); + permanentidreq_vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_PERMANENT_ID_REQ, 0, TAG_ANY); + + if (!fullauthidreq_vp || + anyidreq_vp != NULL || + permanentidreq_vp != NULL) { + ERROR("start message has %sanyidreq, %sfullauthid and %spermanentid. Illegal combination.\n", + (anyidreq_vp != NULL ? "a ": "no "), + (fullauthidreq_vp != NULL ? "a ": "no "), + (permanentidreq_vp != NULL ? "a ": "no ")); + return 0; + } + + /* okay, we have just any_id_req there, so fill in response */ + + /* mark the subtype as being EAP-SIM/Response/Start */ + newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_SUBTYPE, 0); + newvp->vp_integer = EAPSIM_START; + fr_pair_replace(&(rep->vps), newvp); + + /* insert selected version into response. */ + { + uint16_t no_versions; + + no_versions = htons(selectedversion); + + newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_SELECTED_VERSION, 0); + fr_pair_value_memcpy(newvp, (uint8_t *) &no_versions, 2); + fr_pair_replace(&(rep->vps), newvp); + + /* record the selected version */ + memcpy(eap_context->eap.sim.keys.versionselect, &no_versions, 2); + } + + vp = newvp = NULL; + + { + uint32_t nonce[4]; + uint8_t *p; + /* + * insert a nonce_mt that we make up. + */ + nonce[0]=fr_rand(); + nonce[1]=fr_rand(); + nonce[2]=fr_rand(); + nonce[3]=fr_rand(); + + newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_NONCE_MT, 0); + + p = talloc_zero_array(newvp, uint8_t, 18); /* 18 = 16 bytes of nonce + padding */ + memcpy(&p[2], nonce, 16); + fr_pair_value_memsteal(newvp, p); + + fr_pair_replace(&(rep->vps), newvp); + + /* also keep a copy of the nonce! */ + memcpy(eap_context->eap.sim.keys.nonce_mt, nonce, 16); + } + + { + uint16_t idlen; + uint8_t *p; + uint16_t no_idlen; + + /* + * insert the identity here. + */ + vp = fr_pair_find_by_num(rep->vps, PW_USER_NAME, 0, TAG_ANY); + if (!vp) + { + ERROR("eap-sim: We need to have a User-Name attribute!\n"); + return 0; + } + newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_IDENTITY, 0); + + idlen = strlen(vp->vp_strvalue); + p = talloc_zero_array(newvp, uint8_t, idlen + 2); + no_idlen = htons(idlen); + memcpy(p, &no_idlen, 2); + memcpy(p + 2, vp->vp_strvalue, idlen); + fr_pair_value_memsteal(newvp, p); + + fr_pair_replace(&(rep->vps), newvp); + + /* record it */ + memcpy(eap_context->eap.sim.keys.identity, vp->vp_strvalue, idlen); + eap_context->eap.sim.keys.identitylen = idlen; + } + + ki = fr_pair_find_by_num(req->vps, PW_EAP_SIM_KI, 0, TAG_ANY); + if (ki && !fr_pair_find_by_num(req->vps, PW_EAP_SIM_RAND1, 0, TAG_ANY)) { + generate_triplets(req, ki, NULL); + } + + return 1; +} + + +/* + * we got an EAP-Request/Sim/Challenge message in a legal state. + * + * use the RAND challenge to produce the SRES result, and then + * use that to generate a new MAC. + * + * for the moment, we ignore the RANDs, then just plug in the SRES + * values. + * + */ +static int rc_process_eap_challenge(rc_eap_context_t *eap_context, + RADIUS_PACKET *req, RADIUS_PACKET *rep) +{ + VALUE_PAIR *newvp; + VALUE_PAIR *mac, *randvp; + VALUE_PAIR *sres1,*sres2,*sres3; + VALUE_PAIR *Kc1, *Kc2, *Kc3; + uint8_t calcmac[20]; + + /* look for the AT_MAC and the challenge data */ + mac = fr_pair_find_by_num(req->vps, PW_EAP_SIM_MAC, 0, TAG_ANY); + randvp= fr_pair_find_by_num(req->vps, PW_EAP_SIM_RAND, 0, TAG_ANY); + if (!mac || !randvp) { + ERROR("challenge message needs to contain RAND and MAC\n"); + return 0; + } + + /* + * compare RAND with randX, to verify this is the right response + * to this challenge. + */ + { + VALUE_PAIR *randcfgvp[3]; + uint8_t const *randcfg[3]; + + randcfg[0] = &randvp->vp_octets[2]; + randcfg[1] = &randvp->vp_octets[2+EAPSIM_RAND_SIZE]; + randcfg[2] = &randvp->vp_octets[2+EAPSIM_RAND_SIZE*2]; + + randcfgvp[0] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND1, 0, TAG_ANY); + randcfgvp[1] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND2, 0, TAG_ANY); + randcfgvp[2] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND3, 0, TAG_ANY); + + if (!randcfgvp[0] || + !randcfgvp[1] || + !randcfgvp[2]) { + int i; + VALUE_PAIR *ki; + + /* + * Generate a new RAND value, and derive Kc and SRES from + * Ki, but only if we don't already have the random + * numbers. + */ + ki = eap_context->ki; + if (!ki) { + ERROR("Need EAP-SIM-Rand1, EAP-SIM-Rand2, and EAP-SIM-Rand3\n"); + return 0; + } + + for (i = 0; i < 3; i++) { + fr_pair_delete_by_num(&req->vps, PW_EAP_SIM_RAND1 + i, 0, TAG_ANY); + fr_pair_delete_by_num(&req->vps, PW_EAP_SIM_SRES1 + i, 0, TAG_ANY); + fr_pair_delete_by_num(&req->vps, PW_EAP_SIM_KC1 + i, 0, TAG_ANY); + } + + generate_triplets(rep, ki, randvp->vp_octets + 2); + + randcfgvp[0] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND1, 0, TAG_ANY); + randcfgvp[1] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND2, 0, TAG_ANY); + randcfgvp[2] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND3, 0, TAG_ANY); + + if (!randcfgvp[0] || + !randcfgvp[1] || + !randcfgvp[2]) { + ERROR("Failed to create triplets\n"); + return 0; + } + } + + if (memcmp(randcfg[0], randcfgvp[0]->vp_octets, EAPSIM_RAND_SIZE)!=0 || + memcmp(randcfg[1], randcfgvp[1]->vp_octets, EAPSIM_RAND_SIZE)!=0 || + memcmp(randcfg[2], randcfgvp[2]->vp_octets, EAPSIM_RAND_SIZE)!=0) { + int rnum, i; + + ERROR("one of rand 1,2,3 didn't match\n"); + for (rnum = 0; rnum < 3; rnum++) { + ERROR("rand %d\trecv\tconfig\n", rnum); + for (i = 0; i < EAPSIM_RAND_SIZE; i++) { + fprintf(fr_log_fp, "\t%02x\t%02x\n", + randcfg[rnum][i], randcfgvp[rnum]->vp_octets[i]); + } + } + return 0; + } + } + + /* + * now dig up the sres values from the response packet, + * which were put there when we read things in. + * + * Really, they should be calculated from the RAND! + * + */ + sres1 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_SRES1, 0, TAG_ANY); + sres2 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_SRES2, 0, TAG_ANY); + sres3 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_SRES3, 0, TAG_ANY); + + if (!sres1 || + !sres2 || + !sres3) { + ERROR("needs to have sres1, 2 and 3 set.\n"); + return 0; + } + memcpy(eap_context->eap.sim.keys.sres[0], sres1->vp_strvalue, sizeof(eap_context->eap.sim.keys.sres[0])); + memcpy(eap_context->eap.sim.keys.sres[1], sres2->vp_strvalue, sizeof(eap_context->eap.sim.keys.sres[1])); + memcpy(eap_context->eap.sim.keys.sres[2], sres3->vp_strvalue, sizeof(eap_context->eap.sim.keys.sres[2])); + + Kc1 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_KC1, 0, TAG_ANY); + Kc2 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_KC2, 0, TAG_ANY); + Kc3 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_KC3, 0, TAG_ANY); + + if (!Kc1 || + !Kc2 || + !Kc3) { + ERROR("needs to have Kc1, 2 and 3 set.\n"); + return 0; + } + memcpy(eap_context->eap.sim.keys.Kc[0], Kc1->vp_strvalue, sizeof(eap_context->eap.sim.keys.Kc[0])); + memcpy(eap_context->eap.sim.keys.Kc[1], Kc2->vp_strvalue, sizeof(eap_context->eap.sim.keys.Kc[1])); + memcpy(eap_context->eap.sim.keys.Kc[2], Kc3->vp_strvalue, sizeof(eap_context->eap.sim.keys.Kc[2])); + + /* all set, calculate keys */ + eapsim_calculate_keys(&eap_context->eap.sim.keys); + + if (rad_debug_lvl > 2) { + eapsim_dump_mk(&eap_context->eap.sim.keys); + } + + /* verify the MAC, now that we have all the keys. */ + if (eapsim_checkmac(NULL, req->vps, eap_context->eap.sim.keys.K_aut, + eap_context->eap.sim.keys.nonce_mt, sizeof(eap_context->eap.sim.keys.nonce_mt), + calcmac)) { + DEBUG2("MAC check succeed\n"); + } else { + int i, j; + j=0; + DEBUG("calculated MAC (\n"); + for (i = 0; i < 20; i++) { + if (j==4) { + printf("_"); + j=0; + } + j++; + + DEBUG("%02x\n", calcmac[i]); + } + DEBUG("did not match\n"); + return 0; + } + + /* form new response clear of any EAP stuff */ + rc_cleanresp(rep); + + /* mark the subtype as being EAP-SIM/Response/Start */ + newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_SUBTYPE, 0); + newvp->vp_integer = EAPSIM_CHALLENGE; + fr_pair_replace(&(rep->vps), newvp); + + { + uint8_t *p; + /* + * fill the SIM_MAC with a field that will in fact get appended + * to the packet before the MAC is calculated + */ + newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_MAC, 0); + + p = talloc_zero_array(newvp, uint8_t, EAPSIM_SRES_SIZE*3); + memcpy(p+EAPSIM_SRES_SIZE * 0, sres1->vp_strvalue, EAPSIM_SRES_SIZE); + memcpy(p+EAPSIM_SRES_SIZE * 1, sres2->vp_strvalue, EAPSIM_SRES_SIZE); + memcpy(p+EAPSIM_SRES_SIZE * 2, sres3->vp_strvalue, EAPSIM_SRES_SIZE); + fr_pair_value_memsteal(newvp, p); + + fr_pair_replace(&(rep->vps), newvp); + } + + newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_KEY, 0); + fr_pair_value_memcpy(newvp, eap_context->eap.sim.keys.K_aut, EAPSIM_AUTH_SIZE); + + fr_pair_replace(&(rep->vps), newvp); + + return 1; +} + +/* + * this code runs the EAP-SIM client state machine. + * the *request* is from the server. + * the *reponse* is to the server. + * + */ +static int rc_respond_eap_sim(rc_eap_context_t *eap_context, + RADIUS_PACKET *req, RADIUS_PACKET *resp) +{ + enum eapsim_clientstates state, newstate; + enum eapsim_subtype subtype, newsubtype; + VALUE_PAIR *vp, *statevp, *radstate, *eapid; + char statenamebuf[32], subtypenamebuf[32]; + + if ((radstate = fr_pair_list_copy_by_num(NULL, req->vps, PW_STATE, 0, TAG_ANY)) == NULL) + { + return 0; + } + + if ((eapid = fr_pair_list_copy_by_num(NULL, req->vps, PW_EAP_ID, 0, TAG_ANY)) == NULL) + { + return 0; + } + + /* first, dig up the state from the request packet, setting + * ourselves to be in EAP-SIM-Start state if there is none. + */ + + if ((statevp = fr_pair_find_by_num(resp->vps, PW_EAP_SIM_STATE, 0, TAG_ANY)) == NULL) + { + /* must be initial request */ + statevp = fr_pair_afrom_num(resp, PW_EAP_SIM_STATE, 0); + statevp->vp_integer = EAPSIM_CLIENT_INIT; + fr_pair_replace(&(resp->vps), statevp); + } + state = statevp->vp_integer; + + /* + * map the attributes, and authenticate them. + */ + rc_unmap_eapsim_types(req); + + if ((vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_SUBTYPE, 0, TAG_ANY)) == NULL) + { + return 0; + } + subtype = vp->vp_integer; + + DEBUG2("IN state %s subtype %s\n", + sim_state2name(state, statenamebuf, sizeof(statenamebuf)), + sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf))); + + /* + * look for the appropriate state, and process incoming message + */ + switch (state) { + case EAPSIM_CLIENT_INIT: + switch (subtype) { + case EAPSIM_START: + newstate = rc_process_eap_start(eap_context, req, resp); + break; + + case EAPSIM_CHALLENGE: + case EAPSIM_NOTIFICATION: + case EAPSIM_REAUTH: + default: + ERROR("sim in state %s message %s is illegal. Reply dropped.\n", + sim_state2name(state, statenamebuf, sizeof(statenamebuf)), + sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf))); + /* invalid state, drop message */ + return 0; + } + break; + + case EAPSIM_CLIENT_START: + switch (subtype) { + case EAPSIM_START: + /* NOT SURE ABOUT THIS ONE, retransmit, I guess */ + newstate = rc_process_eap_start(eap_context, req, resp); + break; + + case EAPSIM_CHALLENGE: + newstate = rc_process_eap_challenge(eap_context, req, resp); + break; + + default: + ERROR("sim in state %s message %s is illegal. Reply dropped.\n", + sim_state2name(state, statenamebuf, sizeof(statenamebuf)), + sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf))); + /* invalid state, drop message */ + return 0; + } + break; + + + default: + ERROR("sim in illegal state %s\n", + sim_state2name(state, statenamebuf, sizeof(statenamebuf))); + return 0; + } + + /* copy the eap state object in */ + fr_pair_replace(&(resp->vps), eapid); + + /* update stete info, and send new packet */ + rc_map_eapsim_types(resp); + + /* copy the radius state object in */ + fr_pair_replace(&(resp->vps), radstate); + + vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_SUBTYPE, 0, TAG_ANY); + newsubtype = vp->vp_integer; + + + DEBUG2("MOVE from state %s subtype %s\n", + sim_state2name(state, statenamebuf, sizeof(statenamebuf)), + sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf))); + + DEBUG2(" to state %s subtype %s\n", + sim_state2name(newstate, statenamebuf, sizeof(statenamebuf)), + sim_subtype2name(newsubtype, subtypenamebuf, sizeof(subtypenamebuf))); + + statevp->vp_integer = newstate; + return 1; +} + +static int rc_respond_eap_md5(rc_eap_context_t *eap_context, + RADIUS_PACKET *req, RADIUS_PACKET *rep) +{ + VALUE_PAIR *vp, *id, *state; + size_t valuesize; + uint8_t identifier; + uint8_t const *value; + FR_MD5_CTX context; + uint8_t response[16]; + + rc_cleanresp(rep); + + if ((state = fr_pair_list_copy_by_num(NULL, req->vps, PW_STATE, 0, TAG_ANY)) == NULL) + { + ERROR("no state attribute found\n"); + return 0; + } + + if ((id = fr_pair_list_copy_by_num(NULL, req->vps, PW_EAP_ID, 0, TAG_ANY)) == NULL) + { + ERROR("no EAP-ID attribute found\n"); + return 0; + } + identifier = id->vp_integer; + + if ((vp = fr_pair_find_by_num(req->vps, PW_EAP_TYPE_BASE+PW_EAP_MD5, 0, TAG_ANY)) == NULL) + { + ERROR("no EAP-MD5 attribute found\n"); + return 0; + } + + /* got the details of the MD5 challenge */ + valuesize = vp->vp_octets[0]; + value = &vp->vp_octets[1]; + + /* sanitize items */ + if (valuesize > vp->vp_length) + { + ERROR("md5 valuesize if too big (%u > %u)\n", + (unsigned int) valuesize, (unsigned int) vp->vp_length); + return 0; + } + + /* now do the CHAP operation ourself, rather than build the + * buffer. We could also call rad_chap_encode, but it wants + * a CHAP-Challenge, which we don't want to bother with. + */ + fr_md5_init(&context); + fr_md5_update(&context, &identifier, 1); + fr_md5_update(&context, (uint8_t *) eap_context->password, strlen(eap_context->password)); + fr_md5_update(&context, value, valuesize); + fr_md5_final(response, &context); + + { + uint8_t *p; + uint8_t lg_response; + + vp = fr_pair_afrom_num(rep, PW_EAP_TYPE_BASE+PW_EAP_MD5, 0); + vp->vp_length = 17; + + p = talloc_zero_array(vp, uint8_t, 17); + lg_response = 16; + memcpy(p, &lg_response, 1); + memcpy(p + 1, response, 16); + fr_pair_value_memsteal(vp, p); + } + fr_pair_replace(&(rep->vps), vp); + + fr_pair_replace(&(rep->vps), id); + + /* copy the state object in */ + fr_pair_replace(&(rep->vps), state); + + return 1; +} + + +/** Allocate a new socket, and add it to the packet list. + */ +static void rc_add_socket(fr_ipaddr_t *src_ipaddr, uint16_t src_port, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port) +{ + int mysockfd; + + /* Trace what we're doing. */ + char src_addr[15+1] = ""; + char dst_addr[15+1] = ""; + inet_ntop(AF_INET, &(src_ipaddr->ipaddr.ip4addr.s_addr), src_addr, sizeof(src_addr)); + inet_ntop(AF_INET, &(dst_ipaddr->ipaddr.ip4addr.s_addr), dst_addr, sizeof(dst_addr)); + + INFO("Adding new socket: src: %s:%d, dst: %s:%d", src_addr, src_port, dst_addr, dst_port); + + mysockfd = fr_socket(src_ipaddr, src_port); + if (mysockfd < 0) { + ERROR("Failed to create new socket: %s\n", fr_strerror()); + exit(1); + } + + if (!fr_packet_list_socket_add(pl, mysockfd, ipproto, dst_ipaddr, dst_port, NULL)) { + ERROR("Failed to add new socket: %s\n", fr_strerror()); + exit(1); + } + + num_sockets ++; + DEBUG("Added new socket: %d (num sockets: %d)\n", mysockfd, num_sockets); +} + +/** Send one packet for a transaction. + */ +static int rc_send_one_packet(rc_transaction_t *trans, RADIUS_PACKET **packet_p) +{ + if (!trans || !packet_p || !*packet_p) return -1; + + assert(pl != NULL); + + RADIUS_PACKET *packet = *packet_p; + + if (packet->id == -1) { + /* Haven't sent the packet yet. Initialize it. */ + bool rcode; + int i; + + rc_build_eap_context(trans); /* In case of EAP, build EAP-Message and initialize EAP context. */ + + assert(trans->reply == NULL); + + trans->tries = 0; + packet->src_ipaddr.af = server_ipaddr.af; + int nb_sock_add = 0; + while (1) { + /* Allocate a RADIUS packet ID from a suitable socket of the packet list. */ + rcode = fr_packet_list_id_alloc(pl, ipproto, packet_p, NULL); + + if (rcode) { /* Got an ID. */ + break; + } + if (nb_sock_add >= 1) { + ERROR("Added %d new socket(s), but still could not get an ID (currently: %d outgoing requests).\n", + nb_sock_add, fr_packet_list_num_outgoing(pl)); + exit(1); + } + + /* Could not find a free packet ID. Allocate a new socket, then try again. */ + rc_add_socket(&packet->src_ipaddr, packet->src_port, &packet->dst_ipaddr, packet->dst_port); + + nb_sock_add ++; + } + + assert(packet->id != -1); + assert(packet->data == NULL); + + for (i = 0; i < 4; i++) { + ((uint32_t *) packet->vector)[i] = fr_rand(); + } + } + + /* + * Send the packet. + */ + DEBUG2("Transaction: %u, sending packet: %u (id: %u)...\n", trans->id, trans->num_packet, packet->id); + + gettimeofday(&packet->timestamp, NULL); /* set outgoing packet timestamp. */ + + if (rad_send(packet, NULL, secret) < 0) { + ERROR("Failed to send packet (sockfd: %d, id: %d): %s\n", + packet->sockfd, packet->id, fr_strerror()); + } + + trans->num_packet ++; + trans->tries ++; + + if (fr_debug_lvl > 0) fr_packet_header_print(fr_log_fp, packet, false); + if (fr_debug_lvl > 0) vp_printlist(fr_log_fp, packet->vps); + + return 1; +} + +/** Send current packet of a transaction. Arm timeout event. + */ +static int rc_send_transaction_packet(rc_transaction_t *trans, RADIUS_PACKET **packet_p) +// note: we need a 'RADIUS_PACKET **' for fr_packet_list_id_alloc. +{ + if (!trans || !packet_p || !*packet_p) return -1; + + int ret = rc_send_one_packet(trans, packet_p); + if (ret == 1) { + /* Send successful: arm the timeout callback. */ + rc_evprep_packet_timeout(trans); + } + return ret; +} + +/** Deallocate RADIUS packet ID. + */ +static void rc_deallocate_id(rc_transaction_t *trans) +{ + if (!trans || !trans->packet || + (trans->packet->id < 0)) { + return; + } + + RADIUS_PACKET *packet = trans->packet; + + DEBUG2("Deallocating (sockfd: %d, id: %d)\n", packet->sockfd, packet->id); + + /* + * One more unused RADIUS ID. + */ + fr_packet_list_id_free(pl, packet, true); + /* note: "true" means automatically yank, so we must *not* yank ourselves before calling (otherwise, it does nothing) + * so, *don't*: fr_packet_list_yank(pl, request->packet); */ + + /* free more stuff to ensure next allocate won't be stuck on a "full" socket. */ + packet->id = -1; + packet->sockfd = -1; + packet->src_ipaddr.af = AF_UNSPEC; + packet->src_port = 0; + + /* + * If we've already sent a packet, free up the old one, + * and ensure that the next packet has a unique + * authentication vector. + */ + if (packet->data) { + talloc_free(packet->data); + packet->data = NULL; + } + + if (trans->reply) rad_free(&trans->reply); +} + +/** Receive one packet, maybe. + */ +static int rc_recv_one_packet(struct timeval *tv_wait_time) +{ + fd_set set; + struct timeval tv; + rc_transaction_t *trans; + RADIUS_PACKET *reply, **packet_p; + volatile int max_fd; + bool ongoing_trans = false; + char buffer[128]; + + /* Wait for reply, timing out as necessary */ + FD_ZERO(&set); + + max_fd = fr_packet_list_fd_set(pl, &set); + if (max_fd < 0) { + /* no sockets to listen on! */ + return 0; + } + + if (NULL == tv_wait_time) { + timerclear(&tv); + } else { + tv.tv_sec = tv_wait_time->tv_sec; + tv.tv_usec = tv_wait_time->tv_usec; + } + + if (select(max_fd, &set, NULL, NULL, &tv) <= 0) { + /* No packet was received. */ + return 0; + } + + /* + * Receive the reply. + */ + reply = fr_packet_list_recv(pl, &set); + if (!reply) { + ERROR("Received bad packet: %s\n", fr_strerror()); + return -1; /* bad packet */ + } + + /* + * Look for the packet which matches the reply. + */ + reply->src_ipaddr = server_ipaddr; + reply->src_port = server_port; + + /* + * Note: this only works if all packets have the same destination (IP, port). + * We should handle a list of destinations. But we don't. radclient doesn't do it either). + */ + + packet_p = fr_packet_list_find_byreply(pl, reply); + + if (!packet_p) { + /* got reply to packet we didn't send. + * (or maybe we sent it, got no response, freed the ID. Then server responds to first request.) + */ + DEBUG("No outstanding request was found for reply from %s, port %d (sockfd: %d, id: %d)\n", + inet_ntop(reply->src_ipaddr.af, &reply->src_ipaddr.ipaddr, buffer, sizeof(buffer)), + reply->src_port, reply->sockfd, reply->id); + rad_free(&reply); + return -1; + } + + trans = fr_packet2myptr(rc_transaction_t, packet, packet_p); + + if (trans->event) fr_event_delete(ev_list, &trans->event); + + /* + * Fails the signature validation: not a valid reply. + */ + if (rad_verify(reply, trans->packet, secret) < 0) { + /* shared secret is incorrect. + * (or maybe this is a response to another packet we sent, for which we got no response, + * freed the ID, then reused it. Then server responds to first packet.) + */ + DEBUG("Conflicting response authenticator for reply from %s (sockfd: %d, id: %d)\n", + inet_ntop(reply->src_ipaddr.af, &reply->src_ipaddr.ipaddr, buffer, sizeof(buffer)), + reply->sockfd, reply->id); + + goto packet_done; + } + + /* Set reply destination = packet source. */ + reply->dst_ipaddr = trans->packet->src_ipaddr; + reply->dst_port = trans->packet->src_port; + + trans->reply = reply; + reply = NULL; + + if (rad_decode(trans->reply, trans->packet, secret) != 0) { + /* This can fail if packet contains too many attributes. */ + DEBUG("Failed decoding reply\n"); + goto packet_done; + } + + gettimeofday(&trans->reply->timestamp, NULL); /* set received packet timestamp. */ + + if (trans->eap_context) { + /* Call unmap before packet print (so we can see the decoded EAP stuff). */ + rc_unmap_eap_methods(trans->reply); + } + + DEBUG2("Transaction: %u, received packet (id: %u).\n", trans->id, trans->reply->id); + + if (fr_debug_lvl > 0) fr_packet_header_print(fr_log_fp, trans->reply, true); + if (fr_debug_lvl > 0) vp_printlist(fr_log_fp, trans->reply->vps); + + if (!trans->eap_context) { + goto packet_done; + } + + /* now look for the code type. */ + VALUE_PAIR *vp, *vpnext; + for (vp = trans->reply->vps; vp != NULL; vp = vpnext) { + vpnext = vp->next; + + switch (vp->da->attr) { + default: + break; + + case PW_EAP_TYPE_BASE + PW_EAP_MD5: + if (rc_respond_eap_md5(trans->eap_context, trans->reply, trans->packet) && trans->eap_context->eap.md5.tried < 3) + { + /* answer the challenge from server. */ + trans->eap_context->eap.md5.tried ++; + rc_deallocate_id(trans); + rc_send_transaction_packet(trans, &trans->packet); + ongoing_trans = true; // don't free the transaction yet. + } + goto packet_done; + + case PW_EAP_TYPE_BASE + PW_EAP_SIM: + if (rc_respond_eap_sim(trans->eap_context, trans->reply, trans->packet)) { + /* answer the challenge from server. */ + rc_deallocate_id(trans); + rc_send_transaction_packet(trans, &trans->packet); + ongoing_trans = true; // don't free the transaction yet. + } + goto packet_done; + } + } + + /* EAP transaction ends here (no more requests from EAP server). */ + + /* + * success: if we have EAP-Code = Success, and reply is an Access-Accept. + */ + if (trans->reply->code != PW_CODE_ACCESS_ACCEPT) { + DEBUG("EAP transaction finished, but reply is not an Access-Accept"); + goto packet_done; + } + vp = fr_pair_find_by_num(trans->reply->vps, PW_EAP_CODE, 0, TAG_ANY); + if ( (!vp) || (vp->vp_integer != 3) ) { + DEBUG("EAP transaction finished, but reply does not contain EAP-Code = Success"); + goto packet_done; + } + + goto packet_done; + +packet_done: + + /* Basic statistics (salvaged from old code). TODO: something better. */ + if (trans->reply) { + if (trans->reply->code == PW_CODE_ACCESS_ACCEPT) { + totalapp ++; + } else if (trans->reply->code == PW_CODE_ACCESS_REJECT) { + totaldeny ++; + } + } + + rad_free(&trans->reply); + rad_free(&reply); /* may be NULL */ + + if (!ongoing_trans) { + rc_deallocate_id(trans); + rc_finish_transaction(trans); + } + + return 1; +} + +/** Event callback: packet timeout. + */ +static void rc_evcb_packet_timeout(void *ctx) +{ + rc_transaction_t *trans = ctx; + if (!trans || !trans->packet) return; + + DEBUG("Timeout for transaction: %d, tries (so far): %d (max: %d)", trans->id, trans->tries, retries); + + if (trans->event) fr_event_delete(ev_list, &trans->event); + + if (trans->tries < retries) { + /* Try again. */ + rc_send_transaction_packet(trans, &trans->packet); + } else { + DEBUG("No response for transaction: %d, giving up", trans->id); + rc_finish_transaction(trans); + } +} + +/** Prepare event: packet timeout. + */ +static void rc_evprep_packet_timeout(rc_transaction_t *trans) +{ + struct timeval tv_event; + gettimeofday(&tv_event, NULL); + timeradd(&tv_event, &tv_timeout, &tv_event); + + if (!fr_event_insert(ev_list, rc_evcb_packet_timeout, (void *)trans, &tv_event, &trans->event)) { + ERROR("Failed to insert event\n"); + exit(1); + } +} + +/** Trigger all armed events for which time is reached. + */ +static int rc_loop_events(void) +{ + struct timeval when; + uint32_t nb_processed = 0; + + if (!fr_event_list_num_elements(ev_list)) return 0; + + while (1) { + gettimeofday(&when, NULL); + if (!fr_event_run(ev_list, &when)) { + /* no more. */ + break; + } + nb_processed ++; + } + return nb_processed; +} + +/** Receive loop. + * Handle incoming packets, until nothing more is received. + */ +static int dhb_loop_recv(void) +{ + uint32_t nb_received = 0; + while (rc_recv_one_packet(NULL) > 0) { + nb_received ++; + } + return nb_received; +} + +/** Loop starting new transactions, until a limit is reached + * (max parallelism, or no more input available.) + */ +static int rc_loop_start_transactions(void) +{ + int nb_started = 0; + + while (1) { + if (num_ongoing >= parallel) break; + + /* Try to initialize a new transaction. */ + rc_transaction_t *trans = rc_init_transaction(autofree); + if (!trans) break; + + nb_started ++; + rc_send_transaction_packet(trans, &trans->packet); + } + return nb_started; +} + +/** Main loop: Handle events. Receive and process responses. Start new transactions. + * Until we're done. + */ +static void rc_main_loop(void) +{ + while (1) { + /* Handle events. */ + rc_loop_events(); + + /* Receive and process response until no more are received (don't wait). */ + dhb_loop_recv(); + + /* Start new transactions and send the associated packet. */ + rc_loop_start_transactions(); + + /* Check if we're done. */ + if ( (rc_vps_list_in.size == 0) + && (fr_packet_list_num_outgoing(pl) == 0) ) { + break; + } + } + INFO("Main loop: done."); +} + + +void set_radius_dir(TALLOC_CTX *ctx, char const *path) +{ + if (radius_dir) { + char *p; + + memcpy(&p, &radius_dir, sizeof(p)); + talloc_free(p); + radius_dir = NULL; + } + if (path) radius_dir = talloc_strdup(ctx, path); +} + + +/** Set a port from the request type if we don't already have one. + */ +static void rc_get_port(PW_CODE type, uint16_t *port) +{ + switch (type) { + default: + case PW_CODE_ACCESS_REQUEST: + case PW_CODE_ACCESS_CHALLENGE: + case PW_CODE_STATUS_SERVER: + if (*port == 0) *port = getport("radius"); + if (*port == 0) *port = PW_AUTH_UDP_PORT; + return; + + case PW_CODE_ACCOUNTING_REQUEST: + if (*port == 0) *port = getport("radacct"); + if (*port == 0) *port = PW_ACCT_UDP_PORT; + return; + + case PW_CODE_DISCONNECT_REQUEST: + if (*port == 0) *port = PW_POD_UDP_PORT; + return; + + case PW_CODE_COA_REQUEST: + if (*port == 0) *port = PW_COA_UDP_PORT; + return; + + case PW_CODE_UNDEFINED: + if (*port == 0) *port = 0; + return; + } +} + +/** Resolve a port to a request type. + */ +static PW_CODE rc_get_code(uint16_t port) +{ + /* + * getport returns 0 if the service doesn't exist + * so we need to return early, to avoid incorrect + * codes. + */ + if (port == 0) return PW_CODE_UNDEFINED; + + if ((port == getport("radius")) || (port == PW_AUTH_UDP_PORT) || (port == PW_AUTH_UDP_PORT_ALT)) { + return PW_CODE_ACCESS_REQUEST; + } + if ((port == getport("radacct")) || (port == PW_ACCT_UDP_PORT) || (port == PW_ACCT_UDP_PORT_ALT)) { + return PW_CODE_ACCOUNTING_REQUEST; + } + if (port == PW_COA_UDP_PORT) return PW_CODE_COA_REQUEST; + if (port == PW_POD_UDP_PORT) return PW_CODE_DISCONNECT_REQUEST; + + return PW_CODE_UNDEFINED; +} + +/** Resolve server hostname. + */ +static void rc_resolve_hostname(char *server_arg) +{ + if (force_af == AF_UNSPEC) force_af = AF_INET; + server_ipaddr.af = force_af; + if (strcmp(server_arg, "-") != 0) { + char *p; + char const *hostname = server_arg; + char const *portname = server_arg; + char buffer[256]; + + if (*server_arg == '[') { /* IPv6 URL encoded */ + p = strchr(server_arg, ']'); + if ((size_t) (p - server_arg) >= sizeof(buffer)) { + usage(); + } + + memcpy(buffer, server_arg + 1, p - server_arg - 1); + buffer[p - server_arg - 1] = '\0'; + + hostname = buffer; + portname = p + 1; + + } + p = strchr(portname, ':'); + if (p && (strchr(p + 1, ':') == NULL)) { + *p = '\0'; + portname = p + 1; + } else { + portname = NULL; + } + + if (ip_hton(&server_ipaddr, force_af, hostname, false) < 0) { + ERROR("%s: Failed to find IP address for host %s: %s\n", progname, hostname, strerror(errno)); + exit(1); + } + server_addr_init = true; + + /* Strip port from hostname if needed. */ + if (portname) server_port = atoi(portname); + + /* + * Work backwards from the port to determine the packet type + */ + if (packet_code == PW_CODE_UNDEFINED) packet_code = rc_get_code(server_port); + } + rc_get_port(packet_code, &server_port); +} + +int main(int argc, char **argv) +{ + char *p; + int c; + char *filename = NULL; + FILE *fp; + + static fr_log_t radclient_log = { + .colourise = true, + .fd = STDOUT_FILENO, + .dst = L_DST_STDOUT, + .file = NULL, + .debug_file = NULL, + }; + + radlog_init(&radclient_log, false); + + /* + * We probably don't want to free the talloc autofree context + * directly, so we'll allocate a new context beneath it, and + * free that before any leak reports. + */ + autofree = talloc_init("main"); + + fr_debug_lvl = 0; + fr_log_fp = stdout; + + set_radius_dir(autofree, RADIUS_DIR); + + while ((c = getopt(argc, argv, "46c:d:D:f:hp:qst:r:S:xXv")) != EOF) + { + switch (c) { + case '4': + force_af = AF_INET; + break; + case '6': + force_af = AF_INET6; + break; + case 'd': + set_radius_dir(autofree, optarg); + break; + case 'D': + main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg); + break; + case 'f': + filename = optarg; + break; + case 'p': + parallel = atoi(optarg); + if (parallel == 0) parallel = 1; + if (parallel > 65536) parallel = 65536; + break; + case 'q': + do_output = 0; + break; + case 'x': + rad_debug_lvl++; + fr_debug_lvl++; + break; + + case 'X': +#if 0 + sha1_data_problems = 1; /* for debugging only */ +#endif + break; + + case 'r': + if (!isdigit((int) *optarg)) + usage(); + retries = atoi(optarg); + break; + case 's': + do_summary = 1; + break; + case 't': + if (!isdigit((int) *optarg)) + usage(); + timeout = atof(optarg); + break; + case 'v': + printf("$Id$" +#ifndef ENABLE_REPRODUCIBLE_BUILDS + ", built on " __DATE__ " at " __TIME__ +#endif + "\n" + ); + exit(0); + + case 'S': + fp = fopen(optarg, "r"); + if (!fp) { + ERROR("Error opening %s: %s\n", + optarg, fr_syserror(errno)); + exit(1); + } + if (fgets(filesecret, sizeof(filesecret), fp) == NULL) { + ERROR("Error reading %s: %s\n", + optarg, fr_syserror(errno)); + exit(1); + } + fclose(fp); + + /* truncate newline */ + p = filesecret + strlen(filesecret) - 1; + while ((p >= filesecret) && + (*p < ' ')) { + *p = '\0'; + --p; + } + + if (strlen(filesecret) < 2) { + ERROR("Secret in %s is too short\n", optarg); + exit(1); + } + secret = filesecret; + break; + case 'h': + default: + usage(); + } + } + argc -= (optind - 1); + argv += (optind - 1); + + if ((argc < 3) || + ((!secret) && (argc < 4))) { + usage(); + } + + /* Prepare the timeout. */ + rc_float_to_timeval(&tv_timeout, timeout); + + if (!main_config.dictionary_dir) { + main_config.dictionary_dir = DICTDIR; + } + + /* + * Read the distribution dictionaries first, then + * the ones in raddb. + */ + DEBUG2("including dictionary file %s/%s", main_config.dictionary_dir, RADIUS_DICTIONARY); + if (dict_init(main_config.dictionary_dir, RADIUS_DICTIONARY) != 0) { + ERROR("Errors reading dictionary: %s\n", fr_strerror()); + exit(1); + } + + /* + * It's OK if this one doesn't exist. + */ + int rcode = dict_read(radius_dir, RADIUS_DICTIONARY); + if (rcode == -1) { + ERROR("Errors reading %s/%s: %s\n", radius_dir, RADIUS_DICTIONARY, fr_strerror()); + exit(1); + } + + /* + * We print this after reading it. That way if + * it doesn't exist, it's OK, and we don't print + * anything. + */ + if (rcode == 0) { + DEBUG2("Including dictionary file %s/%s", radius_dir, RADIUS_DICTIONARY); + } + + /* + * Get the request type + */ + if (!isdigit((int) argv[2][0])) { + packet_code = fr_str2int(rc_request_types, argv[2], -2); + if (packet_code == -2) { + ERROR("Unrecognised request type \"%s\"\n", argv[2]); + usage(); + } + } else { + packet_code = atoi(argv[2]); + } + + /* + * Resolve hostname. + */ + rc_resolve_hostname(argv[1]); + + /* + * Add the secret. + */ + if (argv[3]) secret = argv[3]; + + /* + * Read input data vp(s) from the file (or stdin). + */ + INFO("Loading input data..."); + if (!rc_load_input(autofree, filename, &rc_vps_list_in, 0) + || rc_vps_list_in.size == 0) { + ERROR("No valid input. Nothing to send.\n"); + exit(EXIT_FAILURE); + } + INFO("Loaded: %d input element(s).", rc_vps_list_in.size); + + /* Initialize the packets list. */ + MEM(pl = fr_packet_list_create(1)); + + /* Initialize the events list. */ + ev_list = fr_event_list_create(autofree, NULL); + if (!ev_list) { + ERROR("Failed to create event list\n"); + exit(1); + } + + /* + * Start main loop. + */ + rc_main_loop(); + + if (do_summary) { + INFO("\n\t Total approved auths: %d", totalapp); + INFO("\t Total denied auths: %d", totaldeny); + } + + talloc_free(autofree); + + return 0; +} + +/** Given a radius request with some attributes in the EAP range, build + * them all into a single EAP-Message body. + * + * If there are multiple eligibles EAP-Type, the first one is picked. + * Function returns 0 if no EAP is involved, or the EAP-Type otherwise. + */ +static int rc_map_eap_methods(RADIUS_PACKET *req) +{ + VALUE_PAIR *vp, *vpnext; + int id, eapcode; + int eap_method = 0; + + eap_packet_t *pt_ep = talloc_zero(req, eap_packet_t); + + vp = fr_pair_find_by_num(req->vps, PW_EAP_ID, 0, TAG_ANY); + if (!vp) { + id = ((int)getpid() & 0xff); + } else { + id = vp->vp_integer; + } + + vp = fr_pair_find_by_num(req->vps, PW_EAP_CODE, 0, TAG_ANY); + if (!vp) { + eapcode = PW_EAP_REQUEST; + } else { + eapcode = vp->vp_integer; + } + + for (vp = req->vps; vp != NULL; vp = vpnext) { + /* save it in case it changes! */ + vpnext = vp->next; + + if (vp->da->attr >= PW_EAP_TYPE_BASE && + vp->da->attr < PW_EAP_TYPE_BASE+256) { + break; + } + } + + if (!vp) { + return 0; + } + + eap_method = vp->da->attr - PW_EAP_TYPE_BASE; + + switch (eap_method) { + case PW_EAP_IDENTITY: + case PW_EAP_NOTIFICATION: + case PW_EAP_NAK: + case PW_EAP_MD5: + case PW_EAP_OTP: + case PW_EAP_GTC: + case PW_EAP_TLS: + case PW_EAP_LEAP: + case PW_EAP_TTLS: + case PW_EAP_PEAP: + default: + /* + * no known special handling, it is just encoded as an + * EAP-message with the given type. + */ + + /* nuke any existing EAP-Messages */ + fr_pair_delete_by_num(&req->vps, PW_EAP_MESSAGE, 0, TAG_ANY); + + pt_ep->code = eapcode; + pt_ep->id = id; + pt_ep->type.num = eap_method; + pt_ep->type.length = vp->vp_length; + + pt_ep->type.data = talloc_memdup(vp, vp->vp_octets, vp->vp_length); + talloc_set_type(pt_ep->type.data, uint8_t); + + eap_basic_compose(req, pt_ep); + } + + return eap_method; +} + +/* + * given a radius request with an EAP-Message body, decode it specific + * attributes. + */ +static void rc_unmap_eap_methods(RADIUS_PACKET *rep) +{ + VALUE_PAIR *eap1; + eap_packet_raw_t *e; + int len; + int type; + + if (!rep) return; + + /* find eap message */ + e = eap_vp2packet(NULL, rep->vps); + if (!e) { + ERROR("failed decoding EAP: %s\n", fr_strerror()); + return; + } + /* create EAP-ID and EAP-CODE attributes to start */ + eap1 = fr_pair_afrom_num(rep, PW_EAP_ID, 0); + eap1->vp_integer = e->id; + fr_pair_add(&(rep->vps), eap1); + + eap1 = fr_pair_afrom_num(rep, PW_EAP_CODE, 0); + eap1->vp_integer = e->code; + fr_pair_add(&(rep->vps), eap1); + + switch (e->code) { + default: + case PW_EAP_SUCCESS: + case PW_EAP_FAILURE: + /* no data */ + break; + + case PW_EAP_REQUEST: + case PW_EAP_RESPONSE: + /* there is a type field, which we use to create + * a new attribute */ + + /* the length was decode already into the attribute + * length, and was checked already. Network byte + * order, just pull it out using math. + */ + len = e->length[0]*256 + e->length[1]; + + /* verify the length is big enough to hold type */ + if (len < 5) + { + talloc_free(e); + return; + } + + type = e->data[0]; + + type += PW_EAP_TYPE_BASE; + len -= 5; + + if (len > MAX_STRING_LEN) { + len = MAX_STRING_LEN; + } + + eap1 = fr_pair_afrom_num(rep, type, 0); + fr_pair_value_memcpy(eap1, e->data + 1, len); + + fr_pair_add(&(rep->vps), eap1); + break; + } + + talloc_free(e); + return; +} + +static int rc_map_eapsim_types(RADIUS_PACKET *r) +{ + int ret; + + eap_packet_t *pt_ep = talloc_zero(r, eap_packet_t); + + ret = map_eapsim_basictypes(r, pt_ep); + + if (ret != 1) { + return ret; + } + + eap_basic_compose(r, pt_ep); + + return 1; +} + +static int rc_unmap_eapsim_types(RADIUS_PACKET *r) +{ + VALUE_PAIR *esvp; + uint8_t *eap_data; + int rcode_unmap; + + esvp = fr_pair_find_by_num(r->vps, PW_EAP_TYPE_BASE+PW_EAP_SIM, 0, TAG_ANY); + if (!esvp) { + ERROR("eap: EAP-Sim attribute not found\n"); + return 0; + } + + eap_data = talloc_memdup(esvp, esvp->vp_octets, esvp->vp_length); + talloc_set_type(eap_data, uint8_t); + + rcode_unmap = unmap_eapsim_basictypes(r, eap_data, esvp->vp_length); + + talloc_free(eap_data); + return rcode_unmap; +} + diff --git a/src/modules/rlm_eap/radeapclient.mk b/src/modules/rlm_eap/radeapclient.mk new file mode 100644 index 0000000..6068f54 --- /dev/null +++ b/src/modules/rlm_eap/radeapclient.mk @@ -0,0 +1,29 @@ +TARGET := radeapclient +SOURCES := radeapclient.c + +SOURCES += ${top_srcdir}/src/main/files.c \ + ${top_srcdir}/src/main/threads.c \ + ${top_srcdir}/src/main/version.c + +TGT_PREREQS := libfreeradius-radius.a libfreeradius-server.a +TGT_LDLIBS := $(LIBS) + +# +# For future work, if we want radeapclient to become radclient +# +ifneq "$(filter libfreeradius-eap%,${ALL_TGTS})" "" +TGT_PREREQS += libfreeradius-eap.a + +ifneq ($(OPENSSL_LIBS),) +SOURCES += ${top_srcdir}/src/main/cb.c ${top_srcdir}/src/main/tls.c +TGT_LDLIBS += $(OPENSSL_LIBS) +endif + +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 diff --git a/src/modules/rlm_eap/rlm_eap.c b/src/modules/rlm_eap/rlm_eap.c new file mode 100644 index 0000000..24b8c5e --- /dev/null +++ b/src/modules/rlm_eap/rlm_eap.c @@ -0,0 +1,814 @@ +/* + * This program is is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * $Id$ + * @file rlm_eap.c + * @brief Implements the EAP framework. + * + * @copyright 2000-2003,2006 The FreeRADIUS server project + * @copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com> + * @copyright 2003 Alan DeKok <aland@freeradius.org> + */ +RCSID("$Id$") + +#include <freeradius-devel/radiusd.h> +#include <freeradius-devel/modules.h> + +#include "rlm_eap.h" + +#include <sys/stat.h> + +static const CONF_PARSER module_config[] = { + { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_t, default_method_name), "md5" }, + { "timer_expire", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_t, timer_limit), "60" }, + { "ignore_unknown_eap_types", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_t, ignore_unknown_types), "no" }, + { "cisco_accounting_username_bug", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_t, mod_accounting_username_bug), "no" }, + { "max_sessions", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_t, max_sessions), "2048" }, + CONF_PARSER_TERMINATOR +}; + +/* + * delete all the allocated space by eap module + */ +static int mod_detach(void *instance) +{ + rlm_eap_t *inst; + + inst = (rlm_eap_t *)instance; + +#ifdef HAVE_PTHREAD_H + pthread_mutex_destroy(&(inst->session_mutex)); +#endif + + rbtree_free(inst->session_tree); + inst->session_tree = NULL; + eaplist_free(inst); + + return 0; +} + + +/* + * Compare two handlers. + */ +static int eap_handler_cmp(void const *a, void const *b) +{ + int rcode; + eap_handler_t const *one = a; + eap_handler_t const *two = b; + + if (one->eap_id < two->eap_id) return -1; + if (one->eap_id > two->eap_id) return +1; + + rcode = memcmp(one->state, two->state, sizeof(one->state)); + if (rcode != 0) return rcode; + + /* + * As of 2.1.8, we don't key off of source IP. This + * a NAS to send packets load-balanced (or fail-over) + * across multiple intermediate proxies, and still have + * EAP work. + */ + if (fr_ipaddr_cmp(&one->src_ipaddr, &two->src_ipaddr) != 0) { + char src1[64], src2[64]; + + fr_ntop(src1, sizeof(src1), &one->src_ipaddr); + fr_ntop(src2, sizeof(src2), &two->src_ipaddr); + + RATE_LIMIT(WARN("EAP packets for one session are arriving from two different upstream" + "servers (%s and %s). Has there been a proxy fail-over?", + src1, src2)); + } + + return 0; +} + + +/* + * read the config section and load all the eap authentication types present. + */ +static int mod_instantiate(CONF_SECTION *cs, void *instance) +{ + int i, ret; + eap_type_t method; + int num_methods; + CONF_SECTION *scs; + rlm_eap_t *inst = instance; + + /* + * Create our own random pool. + */ + for (i = 0; i < 256; i++) { + inst->rand_pool.randrsl[i] = fr_rand(); + } + fr_randinit(&inst->rand_pool, 1); + inst->rand_pool.randcnt = 0; + + 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); + scs != NULL; + scs = cf_subsection_find_next(cs, scs, NULL)) { + char const *name; + + name = cf_section_name1(scs); + if (!name) continue; + + if (!strcmp(name, TLS_CONFIG_SECTION)) continue; + + /* + * Don't break configurations for lazy people who still have LEAP enabled. + */ + if (!strcmp(name, "leap")) { + WARN("rlm_eap (%s): Ignoring EAP method 'leap', because it is no longer supported", + inst->xlat_name); + continue; + } + + /* + * Easier sometimes than commenting out blocks, + * or deleting blocks. + */ + if (!strcmp(name, "disable")) continue; + + method = eap_name2type(name); + if (method == PW_EAP_INVALID) { + cf_log_err_cs(cs, "No dictionary definition for EAP method %s", name); + return -1; + } + + if ((method < PW_EAP_MD5) || (method >= PW_EAP_MAX_TYPES)) { + cf_log_err_cs(cs, "Invalid EAP method %s (unsupported)", name); + return -1; + } + +#if !defined(HAVE_OPENSSL_SSL_H) || !defined(HAVE_LIBSSL) + /* + * This allows the default configuration to be + * shipped with EAP-TLS, etc. enabled. If the + * system doesn't have OpenSSL, they will be + * ignored. + * + * If the system does have OpenSSL, then this + * code will not be used. The administrator will + * then have to delete the tls, + * etc. configurations from eap.conf in order to + * have EAP without the TLS types. + */ + switch (method) { + case PW_EAP_FAST: + 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 + + /* + * Load the type. + */ + ret = eap_module_instantiate(inst, &inst->methods[method], method, scs); + + (void) talloc_get_type_abort(inst->methods[method], eap_module_t); + + if (ret < 0) { + (void) talloc_steal(inst, inst->methods[method]); + return -1; + } + + (void) talloc_steal(inst, inst->methods[method]); + num_methods++; /* successfully loaded one more methods */ + } + + if (num_methods == 0) { + cf_log_err_cs(cs, "No EAP method configured, module cannot do anything"); + return -1; + } + + /* + * Ensure that the default EAP type is loaded. + */ + method = eap_name2type(inst->default_method_name); + if (method == PW_EAP_INVALID) { + cf_log_err_cs(cs, "No dictionary definition for default EAP method '%s'", + inst->default_method_name); + return -1; + } + + if (!inst->methods[method]) { + cf_log_err_cs(cs, "No such sub-type for default EAP method %s", + inst->default_method_name); + return -1; + } + inst->default_method = method; /* save the numerical method */ + + /* + * List of sessions are set to NULL by the memset + * of 'inst', above. + */ + + /* + * Lookup sessions in the tree. We don't free them in + * the tree, as that's taken care of elsewhere... + */ + inst->session_tree = rbtree_create(NULL, eap_handler_cmp, NULL, 0); + if (!inst->session_tree) { + ERROR("rlm_eap (%s): Cannot initialize tree", inst->xlat_name); + return -1; + } + fr_link_talloc_ctx_free(inst, inst->session_tree); + +#ifdef HAVE_PTHREAD_H + if (pthread_mutex_init(&(inst->session_mutex), NULL) < 0) { + ERROR("rlm_eap (%s): Failed initializing mutex: %s", inst->xlat_name, fr_syserror(errno)); + return -1; + } +#endif + + return 0; +} + + +/* + * For backwards compatibility. + */ +static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request) +{ + rlm_eap_t *inst; + eap_handler_t *handler; + eap_packet_raw_t *eap_packet; + eap_rcode_t status; + rlm_rcode_t rcode; + + 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 = %s' for a request that does " + "not contain an EAP-Message attribute!", inst->xlat_name); + return RLM_MODULE_INVALID; + } + + /* + * Get the eap packet to start with + */ + eap_packet = eap_vp2packet(request, request->packet->vps); + if (!eap_packet) { + RERROR("Malformed EAP Message: %s", fr_strerror()); + return RLM_MODULE_FAIL; + } + + /* + * Create the eap handler. The eap_packet will end up being + * "swallowed" into the handler, so we can't access it after + * this call. + */ + handler = eap_handler(inst, &eap_packet, request); + if (!handler) { + RDEBUG2("Failed in handler"); + return RLM_MODULE_INVALID; + } + + /* + * Select the appropriate method or default to the + * configured one + */ + status = eap_method_select(inst, handler); + + /* + * If it failed, die. + */ + if (status == EAP_INVALID) { + eap_fail(handler); + talloc_free(handler); + RDEBUG2("Failed in EAP select"); + return RLM_MODULE_INVALID; + } + +#ifdef WITH_PROXY + /* + * If we're doing horrible tunneling work, remember it. + */ + if ((request->options & RAD_REQUEST_OPTION_PROXY_EAP) != 0) { + RDEBUG2("No EAP proxy set. Not composing EAP"); + /* + * Add the handle to the proxied list, so that we + * can retrieve it in the post-proxy stage, and + * send a response. + */ + handler->inst_holder = inst; + status = request_data_add(request, inst, REQUEST_DATA_EAP_HANDLER, handler, true); + + rad_assert(status == 0); + return RLM_MODULE_HANDLED; + } +#endif + +#ifdef WITH_PROXY + /* + * Maybe the request was marked to be proxied. If so, + * proxy it. + */ + if (request->proxy != NULL) { + VALUE_PAIR *vp = NULL; + + rad_assert(!request->proxy_reply); + + /* + * Add the handle to the proxied list, so that we + * can retrieve it in the post-proxy stage, and + * send a response. + */ + handler->inst_holder = inst; + + status = request_data_add(request, inst, REQUEST_DATA_EAP_HANDLER, handler, true); + + rad_assert(status == 0); + + /* + * Some simple sanity checks. These should really + * be handled by the radius library... + */ + vp = fr_pair_find_by_num(request->proxy->vps, PW_EAP_MESSAGE, 0, TAG_ANY); + if (vp) { + vp = fr_pair_find_by_num(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY); + if (!vp) { + fr_pair_make(request->proxy, + &request->proxy->vps, + "Message-Authenticator", + NULL, T_OP_EQ); + } + } + + /* + * Delete the "proxied to" attribute, as it's + * set to 127.0.0.1 for tunneled requests, and + * we don't want to tell the world that... + */ + fr_pair_delete_by_num(&request->proxy->vps, PW_FREERADIUS_PROXIED_TO, VENDORPEC_FREERADIUS, TAG_ANY); + + RWDEBUG2("Tunneled session will be proxied. Not doing EAP"); + return RLM_MODULE_HANDLED; + } +#endif + + /* + * We are done, wrap the EAP-request in RADIUS to send + * with all other required radius attributes + */ + rcode = eap_compose(handler); + + /* + * Add to the list only if it is EAP-Request. + */ + if ((handler->eap_ds->request->code == PW_EAP_REQUEST) && + (handler->eap_ds->request->type.num >= PW_EAP_MD5)) { + /* + * Return FAIL if we can't remember the handler. + * This is actually disallowed by the + * specification, as unexpected FAILs could have + * been forged. However, we want to signal to + * everyone else involved that we are + * intentionally failing the session, as opposed + * to accidentally failing it. + */ + if (!eaplist_add(inst, handler)) { + RDEBUG("Failed adding handler to the list"); + eap_fail(handler); + talloc_free(handler); + return RLM_MODULE_FAIL; + } + + } else { + /* + * Enable the cached entry on success. + */ + if (handler->eap_ds->request->code == PW_EAP_SUCCESS) { + VALUE_PAIR *vp; + + vp = fr_pair_find_by_num(request->state, PW_TLS_CACHE_FILENAME, 0, TAG_ANY); + if (vp) (void) chmod(vp->vp_strvalue, S_IRUSR | S_IWUSR); + } + + /* + * Disable the cached entry on failure. + */ + if (handler->eap_ds->request->code == PW_EAP_FAILURE) { + VALUE_PAIR *vp; + + vp = fr_pair_find_by_num(request->state, PW_TLS_CACHE_FILENAME, 0, TAG_ANY); + if (vp) (void) unlink(vp->vp_strvalue); + } + + RDEBUG2("Freeing handler"); + /* handler is not required any more, free it now */ + talloc_free(handler); + } + + /* + * If it's an Access-Accept, RFC 2869, Section 2.3.1 + * says that we MUST include a User-Name attribute in the + * Access-Accept. + */ + if ((request->reply->code == PW_CODE_ACCESS_ACCEPT) && + request->username) { + VALUE_PAIR *vp; + + /* + * Doesn't exist, add it in. + */ + vp = fr_pair_find_by_num(request->reply->vps, PW_USER_NAME, 0, TAG_ANY); + if (!vp) { + vp = request->username; + if (vp->da->attr != PW_USER_NAME) { + vp = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY); + } + if (vp) { + vp = fr_pair_copy(request->reply, vp); + fr_pair_add(&request->reply->vps, vp); + } + } + + /* + * Cisco AP1230 has a bug and needs a zero + * terminated string in Access-Accept. This + * means it requires 2 trailing zeros. One to + * send in the RADIUS packet, and the other to + * convince the rest of the server that + * vp->vp_strvalue is still a NUL-terminated C + * string. + */ + if (vp && inst->mod_accounting_username_bug) { + char const *old = vp->vp_strvalue; + char *new; + + vp->vp_length++; /* account for an additional zero */ + + new = talloc_array(vp, char, vp->vp_length + 1); + + memcpy(new, old, vp->vp_length); + new[vp->length] = '\0'; + vp->vp_strvalue = new; + + rad_const_free(old); + VERIFY_VP(vp); + } + } + + return rcode; +} + +/* + * EAP authorization DEPENDS on other rlm authorizations, + * to check for user existence & get their configured values. + * It Handles EAP-START Messages, User-Name initilization. + */ +static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request) +{ + rlm_eap_t *inst; + int status; + VALUE_PAIR *vp; + + inst = (rlm_eap_t *)instance; + +#ifdef WITH_PROXY + /* + * We don't do authorization again, once we've seen the + * proxy reply (or the proxied packet) + */ + if (request->proxy != NULL) + return RLM_MODULE_NOOP; +#endif + + /* + * For EAP_START, send Access-Challenge with EAP Identity + * request. even when we have to proxy this request + * + * RFC 2869, Section 2.3.1 notes that the "domain" of the + * user, (i.e. where to proxy him) comes from the EAP-Identity, + * so we CANNOT proxy the user, until we know his identity. + * + * We therefore send an EAP Identity request. + */ + status = eap_start(inst, request); + switch (status) { + case EAP_NOOP: + return RLM_MODULE_NOOP; + case EAP_FAIL: + return RLM_MODULE_FAIL; + case EAP_FOUND: + return RLM_MODULE_HANDLED; + case EAP_OK: + case EAP_NOTFOUND: + default: + break; + } + + /* + * RFC 2869, Section 2.3.1. If a NAS sends an EAP-Identity, + * it MUST copy the identity into the User-Name attribute. + * + * But we don't worry about that too much. We depend on + * each EAP sub-module to look for handler->request->username, + * and to get excited if it doesn't appear. + */ + vp = fr_pair_find_by_num(request->config, PW_AUTH_TYPE, 0, TAG_ANY); + if ((!vp) || (vp->vp_integer != PW_AUTH_TYPE_REJECT)) { + vp = pair_make_config("Auth-Type", inst->xlat_name, T_OP_EQ); + if (!vp) { + RDEBUG2("Failed to create Auth-Type %s: %s\n", + inst->xlat_name, fr_strerror()); + return RLM_MODULE_FAIL; + } + } else { + RWDEBUG2("Auth-Type already set. Not setting to EAP"); + } + + if (status == EAP_OK) return RLM_MODULE_OK; + + return RLM_MODULE_UPDATED; +} + + +#ifdef WITH_PROXY +/* + * If we're proxying EAP, then there may be magic we need + * to do. + */ +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; + vp_cursor_t cursor; + + /* + * If there was a handler associated with this request, + * then it's a tunneled request which was proxied... + */ + handler = request_data_get(request, inst, REQUEST_DATA_EAP_HANDLER); + if (handler != NULL) { + rlm_rcode_t rcode; + eap_tunnel_data_t *data; + + /* + * Grab the tunnel callbacks from the request. + */ + data = (eap_tunnel_data_t *) request_data_get(request, + request->proxy, + REQUEST_DATA_EAP_TUNNEL_CALLBACK); + if (!data) { + RERROR("Failed to retrieve callback for tunneled session!"); + talloc_free(handler); + return RLM_MODULE_FAIL; + } + + /* + * Do the callback... + */ + RDEBUG2("Doing post-proxy callback"); + rcode = data->callback(handler, data->tls_session); + talloc_free(data); + if (rcode == 0) { + RDEBUG2("Failed in post-proxy callback"); + eap_fail(handler); + talloc_free(handler); + return RLM_MODULE_REJECT; + } + + /* + * We are done, wrap the EAP-request in RADIUS to send + * with all other required radius attributes + */ + eap_compose(handler); + + /* + * Add to the list only if it is EAP-Request. + */ + if ((handler->eap_ds->request->code == PW_EAP_REQUEST) && + (handler->eap_ds->request->type.num >= PW_EAP_MD5)) { + if (!eaplist_add(inst, handler)) { + eap_fail(handler); + talloc_free(handler); + return RLM_MODULE_FAIL; + } + + } else { + RDEBUG2("Freeing handler"); + /* handler is not required any more, free it now */ + talloc_free(handler); + } + + /* + * If it's an Access-Accept, RFC 2869, Section 2.3.1 + * says that we MUST include a User-Name attribute in the + * Access-Accept. + */ + if ((request->reply->code == PW_CODE_ACCESS_ACCEPT) && + request->username) { + /* + * Doesn't exist, add it in. + */ + vp = fr_pair_find_by_num(request->reply->vps, PW_USER_NAME, 0, TAG_ANY); + if (!vp) { + pair_make_reply("User-Name", + request->username->vp_strvalue, + T_OP_EQ); + } + } + + return RLM_MODULE_OK; + } else { + RDEBUG2("No pre-existing handler found"); + } + + /* + * This is allowed. + */ + if (!request->proxy_reply) return RLM_MODULE_NOOP; + + /* + * There may be more than one Cisco-AVPair. + * Ensure we find the one with the LEAP attribute. + */ + fr_cursor_init(&cursor, &request->proxy_reply->vps); + for (;;) { + /* + * Hmm... there's got to be a better way to + * discover codes for vendor attributes. + * + * This is vendor Cisco (9), Cisco-AVPair + * attribute (1) + */ + vp = fr_cursor_next_by_num(&cursor, 1, 9, TAG_ANY); + if (!vp) { + return RLM_MODULE_NOOP; + } + + /* + * If it's "leap:session-key", then stop. + * + * The format is VERY specific! + */ + if (strncasecmp(vp->vp_strvalue, "leap:session-key=", 17) == 0) { + break; + } + } + + /* + * The format is very specific. + */ + if (vp->vp_length != (17 + 34)) { + RDEBUG2("Cisco-AVPair with leap:session-key has incorrect length %zu: Expected %d", + vp->vp_length, 17 + 34); + return RLM_MODULE_NOOP; + } + + /* + * Decrypt the session key, using the proxy data. + * + * Note that the session key is *binary*, and therefore + * may contain embedded zeros. So we have to use memdup. + * However, Cisco-AVPair is a "string", so the rest of the + * code assumes that it's terminated by a trailing '\0'. + * + * So... be sure to (a) use memdup, and (b) include the last + * zero byte. + */ + i = 34; + p = talloc_memdup(vp, vp->vp_strvalue, vp->vp_length + 1); + talloc_set_type(p, uint8_t); + 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; + + 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. + */ + 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; +} +#endif + +static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request) +{ + rlm_eap_t *inst = instance; + VALUE_PAIR *vp; + eap_handler_t *handler; + eap_packet_raw_t *eap_packet; + + /* + * Only build a failure message if something previously rejected the request + */ + vp = fr_pair_find_by_num(request->config, PW_POST_AUTH_TYPE, 0, TAG_ANY); + + if (!vp || (vp->vp_integer != PW_POST_AUTH_TYPE_REJECT)) return RLM_MODULE_NOOP; + + if (!fr_pair_find_by_num(request->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY)) { + RDEBUG3("Request didn't contain an EAP-Message, not inserting EAP-Failure"); + return RLM_MODULE_NOOP; + } + + if (fr_pair_find_by_num(request->reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY)) { + RDEBUG3("Reply already contained an EAP-Message, not inserting EAP-Failure"); + return RLM_MODULE_NOOP; + } + + eap_packet = eap_vp2packet(request, request->packet->vps); + if (!eap_packet) { + RERROR("Malformed EAP Message: %s", fr_strerror()); + return RLM_MODULE_FAIL; + } + + handler = eap_handler(inst, &eap_packet, request); + if (!handler) { + RDEBUG2("Failed to get handler, probably already removed, not inserting EAP-Failure"); + return RLM_MODULE_NOOP; + } + + RDEBUG2("Request was previously rejected, inserting EAP-Failure"); + eap_fail(handler); + talloc_free(handler); + + /* + * Make sure there's a message authenticator attribute in the response + * RADIUS protocol code will calculate the correct value later... + */ + vp = fr_pair_find_by_num(request->reply->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY); + if (!vp) { + pair_make_reply("Message-Authenticator", "0x00", T_OP_EQ); + } + + return RLM_MODULE_UPDATED; +} + +/* + * The module name should be the only globally exported symbol. + * That is, everything else should be 'static'. + */ +extern module_t rlm_eap; +module_t rlm_eap = { + .magic = RLM_MODULE_INIT, + .name = "eap", + .inst_size = sizeof(rlm_eap_t), + .config = module_config, + .instantiate = mod_instantiate, + .detach = mod_detach, + .methods = { + [MOD_AUTHENTICATE] = mod_authenticate, + [MOD_AUTHORIZE] = mod_authorize, +#ifdef WITH_PROXY + [MOD_POST_PROXY] = mod_post_proxy, +#endif + [MOD_POST_AUTH] = mod_post_auth + }, +}; diff --git a/src/modules/rlm_eap/rlm_eap.h b/src/modules/rlm_eap/rlm_eap.h new file mode 100644 index 0000000..384f7f7 --- /dev/null +++ b/src/modules/rlm_eap/rlm_eap.h @@ -0,0 +1,115 @@ +/* + * rlm_eap.h Local Header file. + * + * 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 2001 hereUare Communications, Inc. <raghud@hereuare.com> + * Copyright 2003 Alan DeKok <aland@freeradius.org> + * Copyright 2006 The FreeRADIUS server project + */ +#ifndef _RLM_EAP_H +#define _RLM_EAP_H + +RCSIDH(rlm_eap_h, "$Id$") + +#include <freeradius-devel/modpriv.h> +#include "eap.h" +#include "eap_types.h" + +/* + * Keep track of which sub modules we've loaded. + */ +typedef struct eap_module { + char const *name; + rlm_eap_module_t *type; + fr_dlhandle handle; + CONF_SECTION *cs; + void *instance; +} eap_module_t; + +/* + * This structure contains eap's persistent data. + * sessions = remembered sessions, in a tree for speed. + * types = All supported EAP-Types + * mutex = ensure only one thread is updating the sessions[] struct + */ +typedef struct rlm_eap { + rbtree_t *session_tree; + eap_handler_t *session_head, *session_tail; + eap_module_t *methods[PW_EAP_MAX_TYPES]; + + /* + * Configuration items. + */ + uint32_t timer_limit; + + char const *default_method_name; + eap_type_t default_method; + + bool ignore_unknown_types; + bool mod_accounting_username_bug; + + uint32_t max_sessions; + +#ifdef HAVE_PTHREAD_H + pthread_mutex_t session_mutex; + pthread_mutex_t handler_mutex; +#endif + + char const *xlat_name; /* no xlat's yet */ + fr_randctx rand_pool; +} rlm_eap_t; + +/* + * For simplicity in the rest of the code. + */ +#ifndef HAVE_PTHREAD_H +/* + * This is easier than ifdef's throughout the code. + */ +#define pthread_mutex_init(_x, _y) +#define pthread_mutex_destroy(_x) +#define pthread_mutex_lock(_x) +#define pthread_mutex_unlock(_x) +#endif + +/* function definitions */ +/* EAP-Type */ +int eap_module_instantiate(rlm_eap_t *inst, eap_module_t **method, eap_type_t num, CONF_SECTION *cs); +eap_rcode_t eap_method_select(rlm_eap_t *inst, eap_handler_t *handler); + +/* EAP */ +int eap_start(rlm_eap_t *inst, REQUEST *request) CC_HINT(nonnull); +void eap_fail(eap_handler_t *handler) CC_HINT(nonnull); +void eap_success(eap_handler_t *handler) CC_HINT(nonnull); +rlm_rcode_t eap_compose(eap_handler_t *handler) CC_HINT(nonnull); +eap_handler_t *eap_handler(rlm_eap_t *inst, eap_packet_raw_t **eap_msg, REQUEST *request) CC_HINT(nonnull); + +/* Memory Management */ +EAP_DS *eap_ds_alloc(eap_handler_t *handler); +eap_handler_t *eap_handler_alloc(rlm_eap_t *inst); +void eap_ds_free(EAP_DS **eap_ds); +int eaplist_add(rlm_eap_t *inst, eap_handler_t *handler) CC_HINT(nonnull); +eap_handler_t *eaplist_find(rlm_eap_t *inst, REQUEST *request, eap_packet_raw_t *eap_packet); +void eaplist_free(rlm_eap_t *inst); + +/* State */ +void generate_key(void); +VALUE_PAIR *generate_state(time_t timestamp); +int verify_state(VALUE_PAIR *state, time_t timestamp); + +#endif /*_RLM_EAP_H*/ diff --git a/src/modules/rlm_eap/rlm_eap.mk b/src/modules/rlm_eap/rlm_eap.mk new file mode 100644 index 0000000..4459563 --- /dev/null +++ b/src/modules/rlm_eap/rlm_eap.mk @@ -0,0 +1,6 @@ +TARGET := rlm_eap.a +SOURCES := rlm_eap.c eap.c mem.c + +SRC_INCDIRS := . libeap + +TGT_PREREQS := libfreeradius-eap.a diff --git a/src/modules/rlm_eap/types/all.mk b/src/modules/rlm_eap/types/all.mk new file mode 100644 index 0000000..b85d501 --- /dev/null +++ b/src/modules/rlm_eap/types/all.mk @@ -0,0 +1 @@ +SUBMAKEFILES := $(wildcard ${top_srcdir}/src/modules/rlm_eap/types/rlm_eap_*/all.mk) diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/.gitignore b/src/modules/rlm_eap/types/rlm_eap_fast/.gitignore new file mode 100644 index 0000000..01a5daa --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_fast/.gitignore @@ -0,0 +1 @@ +all.mk diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/all.mk.in b/src/modules/rlm_eap/types/rlm_eap_fast/all.mk.in new file mode 100644 index 0000000..41920f5 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_fast/all.mk.in @@ -0,0 +1,12 @@ +TARGETNAME := @targetname@ + +ifneq "$(OPENSSL_LIBS)" "" +ifneq "$(TARGETNAME)" "" +TARGET := $(TARGETNAME).a +endif +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/configure b/src/modules/rlm_eap/types/rlm_eap_fast/configure new file mode 100755 index 0000000..c2b38b9 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_fast/configure @@ -0,0 +1,4456 @@ +#! /bin/sh +# From configure.ac Revision. +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="rlm_eap_fast.c" +ac_subst_vars='LTLIBOBJS +LIBOBJS +targetname +mod_cflags +mod_ldflags +EGREP +GREP +CPP +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +runstatedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_rlm_eap_fast +with_openssl_lib_dir +with_openssl_include_dir +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir runstatedir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --without-rlm_eap_fast build without rlm_eap_fast + --with-openssl-lib-dir=DIR directory for LDAP library files + --with-openssl-include-dir=DIR directory for LDAP include files + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + +# Check whether --with-rlm_eap_fast was given. +if test "${with_rlm_eap_fast+set}" = set; then : + withval=$with_rlm_eap_fast; +fi + + + +mod_ldflags= +mod_cflags= + +if test x$with_rlm_eap_fast != xno; then + + openssl_lib_dir= + +# Check whether --with-openssl-lib-dir was given. +if test "${with_openssl_lib_dir+set}" = set; then : + withval=$with_openssl_lib_dir; case "$withval" in + no) + as_fn_error $? "Need openssl-lib-dir" "$LINENO" 5 + ;; + yes) + ;; + *) + openssl_lib_dir="$withval" + ;; + esac + +fi + + + openssl_include_dir= + +# Check whether --with-openssl-include-dir was given. +if test "${with_openssl_include_dir+set}" = set; then : + withval=$with_openssl_include_dir; case "$withval" in + no) + as_fn_error $? "Need openssl-include-dir" "$LINENO" 5 + ;; + yes) + ;; + *) + openssl_include_dir="$withval" + ;; + esac + +fi + + + + smart_try_dir=$openssl_include_dir + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + +ac_safe=`echo "openssl/ec.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 openssl/ec.h in $try" >&5 +$as_echo_n "checking for openssl/ec.h in $try... " >&6; } + CPPFLAGS="-isystem $try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <openssl/ec.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}/openssl/ec.h" >&5 +$as_echo_n "checking for ${_prefix}/openssl/ec.h... " >&6; } + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <openssl/ec.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 openssl/ec.h" >&5 +$as_echo_n "checking for openssl/ec.h... " >&6; } + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <openssl/ec.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 try in $_smart_include_dir; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ec.h in $try" >&5 +$as_echo_n "checking for openssl/ec.h in $try... " >&6; } + CPPFLAGS="-isystem $try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <openssl/ec.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 "$ac_cv_header_openssl_ec_h" != "yes"; then + fail="$fail openssl/ec.h" + fi + + smart_try_dir=$openssl_lib_dir + + +sm_lib_safe=`echo "crypto" | sed 'y%./+-%__p_%'` +sm_func_safe=`echo "EVP_CIPHER_CTX_new" | sed 'y%./+-%__p_%'` + +old_LIBS="$LIBS" +old_CPPFLAGS="$CPPFLAGS" +smart_lib= +smart_ldflags= +smart_lib_dir= + +if test "x$smart_try_dir" != "x"; then + for try in $smart_try_dir; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EVP_CIPHER_CTX_new in -lcrypto in $try" >&5 +$as_echo_n "checking for EVP_CIPHER_CTX_new in -lcrypto in $try... " >&6; } + LIBS="-lcrypto $old_LIBS" + CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char EVP_CIPHER_CTX_new(); +int +main () +{ +EVP_CIPHER_CTX_new() + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + smart_lib="-lcrypto" + smart_ldflags="-L$try -Wl,-rpath,$try" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + break + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + LIBS="$old_LIBS" + CPPFLAGS="$old_CPPFLAGS" +fi + +if test "x$smart_lib" = "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EVP_CIPHER_CTX_new in -lcrypto" >&5 +$as_echo_n "checking for EVP_CIPHER_CTX_new in -lcrypto... " >&6; } + LIBS="-lcrypto $old_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char EVP_CIPHER_CTX_new(); +int +main () +{ +EVP_CIPHER_CTX_new() + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + smart_lib="-lcrypto" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$old_LIBS" +fi + +if test "x$smart_lib" = "x"; then + for try in /usr/local/lib /opt/lib; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EVP_CIPHER_CTX_new in -lcrypto in $try" >&5 +$as_echo_n "checking for EVP_CIPHER_CTX_new in -lcrypto in $try... " >&6; } + LIBS="-lcrypto $old_LIBS" + CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char EVP_CIPHER_CTX_new(); +int +main () +{ +EVP_CIPHER_CTX_new() + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + smart_lib="-lcrypto" + smart_ldflags="-L$try -Wl,-rpath,$try" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + break + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + LIBS="$old_LIBS" + CPPFLAGS="$old_CPPFLAGS" +fi + +if test "x$smart_lib" != "x"; then + eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes" + LIBS="$smart_ldflags $smart_lib $old_LIBS" + SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS" +fi + + if test "x$ac_cv_lib_crypto_EVP_CIPHER_CTX_new" != "xyes"; then + fail="libssl" + fi + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <openssl/crypto.h> + #if (OPENSSL_VERSION_NUMBER >= 0x01000100fL) + yes + #endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "yes" >/dev/null 2>&1; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL version >= 1.0.1a" >&5 +$as_echo_n "checking for OpenSSL version >= 1.0.1a... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL version >= 1.0.1a" >&5 +$as_echo_n "checking for OpenSSL version >= 1.0.1a... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fail="openssl>1.0.1" + + +fi +rm -f conftest* + + + targetname=rlm_eap_fast +else + targetname= + echo \*\*\* module rlm_eap_fast is disabled. +fi + +if test x"$fail" != x""; then + if test x"${enable_strict_dependencies}" = x"yes"; then + as_fn_error $? "set --without-rlm_eap_fast to disable it explicitly." "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_eap_fast." >&5 +$as_echo "$as_me: WARNING: silently not building rlm_eap_fast." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_eap_fast requires: $fail." >&5 +$as_echo "$as_me: WARNING: FAILURE: rlm_eap_fast requires: $fail." >&2;} + targetname="" + fi +fi + + + + +ac_config_files="$ac_config_files all.mk" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/configure.ac b/src/modules/rlm_eap/types/rlm_eap_fast/configure.ac new file mode 100644 index 0000000..b872882 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_fast/configure.ac @@ -0,0 +1,98 @@ +AC_PREREQ([2.68]) +AC_INIT(rlm_eap_fast.c) +AC_REVISION($Revision$) +FR_INIT_MODULE([rlm_eap_fast]) + +mod_ldflags= +mod_cflags= + +if test x$with_[]modname != xno; then + + dnl ############################################################ + dnl # Check for command line options + dnl ############################################################ + dnl extra argument: --with-openssl-lib-dir + openssl_lib_dir= + AC_ARG_WITH(openssl-lib-dir, + [ --with-openssl-lib-dir=DIR directory for LDAP library files []], + [ case "$withval" in + no) + AC_MSG_ERROR(Need openssl-lib-dir) + ;; + yes) + ;; + *) + openssl_lib_dir="$withval" + ;; + esac ] + ) + + dnl extra argument: --with-openssl-include-dir + openssl_include_dir= + AC_ARG_WITH(openssl-include-dir, + [ --with-openssl-include-dir=DIR directory for LDAP include files []], + [ case "$withval" in + no) + AC_MSG_ERROR(Need openssl-include-dir) + ;; + yes) + ;; + *) + openssl_include_dir="$withval" + ;; + esac ] + ) + + dnl ############################################################ + dnl # Check for header files + dnl ############################################################ + + smart_try_dir=$openssl_include_dir + FR_SMART_CHECK_INCLUDE(openssl/ec.h) + if test "$ac_cv_header_openssl_ec_h" != "yes"; then + fail="$fail openssl/ec.h" + fi + + smart_try_dir=$openssl_lib_dir + FR_SMART_CHECK_LIB(crypto, EVP_CIPHER_CTX_new) + if test "x$ac_cv_lib_crypto_EVP_CIPHER_CTX_new" != "xyes"; then + fail="libssl" + fi + + AC_EGREP_CPP(yes, + [#include <openssl/crypto.h> + #if (OPENSSL_VERSION_NUMBER >= 0x01000100fL) + yes + #endif + ], + [ + AC_MSG_CHECKING([for OpenSSL version >= 1.0.1a]) + AC_MSG_RESULT(yes) + ], + [ + AC_MSG_CHECKING([for OpenSSL version >= 1.0.1a]) + AC_MSG_RESULT(no) + fail="openssl>1.0.1" + ] + ) + + targetname=modname +else + targetname= + echo \*\*\* module modname is disabled. +fi + +if test x"$fail" != x""; then + if test x"${enable_strict_dependencies}" = x"yes"; then + AC_MSG_ERROR([set --without-]modname[ to disable it explicitly.]) + else + AC_MSG_WARN([silently not building ]modname[.]) + AC_MSG_WARN([FAILURE: ]modname[ requires: $fail.]) + targetname="" + fi +fi + +AC_SUBST(mod_ldflags) +AC_SUBST(mod_cflags) +AC_SUBST(targetname) +AC_OUTPUT(all.mk) 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 index 0000000..bbb5a03 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.c @@ -0,0 +1,1315 @@ +/* + * 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; + int mac_key_len, enc_key_len, fixed_iv_len; + + 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); + RDEBUG3("OpenSSL: cipher nid %d digest nid %d", + cipher, digest); + if (cipher < 0 || digest < 0) + return -1; + if (cipher == NID_undef) { + RDEBUG3("OpenSSL: no cipher in use?!"); + return -1; + } + c = EVP_get_cipherbynid(cipher); + if (!c) + return -1; + enc_key_len = EVP_CIPHER_key_length(c); + if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE || + EVP_CIPHER_mode(c) == EVP_CIPH_CCM_MODE) + fixed_iv_len = 4; /* only part of IV from PRF */ + else + fixed_iv_len = EVP_CIPHER_iv_length(c); + if (digest == NID_undef) { + RDEBUG3("OpenSSL: no digest in use (e.g., AEAD)"); + mac_key_len = 0; + } else { + h = EVP_get_digestbynid(digest); + if (!h) + return -1; + mac_key_len = EVP_MD_size(h); + } + + RDEBUG2("OpenSSL: keyblock size: mac_key_len=%d enc_key_len=%d fixed_iv_len=%d", + mac_key_len, enc_key_len, fixed_iv_len); + return 2 * (mac_key_len + enc_key_len + fixed_iv_len); +#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; + 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)); + + t->keyblock = talloc(t, eap_fast_keyblock_t); + + eap_fast_tls_gen_challenge(tls_session->ssl, SSL_version(tls_session->ssl), buf, 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); +} + +/** + * 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); + if (dlen < 0) return; + + 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; + const int len = sizeof(binding) - (&binding.reserved - (uint8_t *)&binding); + + RDEBUG("Sending Cryptobinding"); + + memset(&binding, 0, sizeof(eap_tlv_crypto_binding_tlv_t)); + 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"); + tls_session->authentication_success = true; + 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: + if (vp->vp_length != CHAP_VALUE_LENGTH) { + wrong_length: + REDEBUG("Found %s with incorrect length. Expected %u, got %zu", + vp->da->name, 16, vp->vp_length); + rcode = RLM_MODULE_INVALID; + break; + } + + + memcpy(t->isk.mppe_send, vp->vp_octets, CHAP_VALUE_LENGTH); + break; + + case PW_MSCHAP_MPPE_RECV_KEY: + if (vp->length != CHAP_VALUE_LENGTH) goto wrong_length; + + 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; + + RDEBUG2("AUTHENTICATION"); + vp = fr_pair_make(fake, &fake->config, "EAP-Type", "0", T_OP_EQ); + vp->vp_integer = t->default_method; + + /* + * 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; + eap_tlv_crypto_binding_tlv_t my_binding; + + 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 && (vp->vp_length >= sizeof(eap_tlv_crypto_binding_tlv_t))) { + binding = &my_binding; + binding->tlv_type = htons(EAP_FAST_TLV_MANDATORY | EAP_FAST_TLV_CRYPTO_BINDING); + binding->length = htons(sizeof(*binding) - 2 * sizeof(uint16_t)); + memcpy(&my_binding.reserved, vp->vp_octets, sizeof(my_binding) - 4); + } + 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 code; + } + + 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; + } + + /* + * Send a new pac at ~0.6 times the lifetime. + */ + if (!t->pac.expires || t->pac.expired || t->pac.expires < (time(NULL) + (t->pac_lifetime >> 1) + (t->pac_lifetime >> 3))) { + 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 (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 index 0000000..8a88bd6 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.h @@ -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 index 0000000..e386e70 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.c @@ -0,0 +1,198 @@ +/* + * 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" + +# define DEBUG if (fr_debug_lvl && fr_log_fp) fr_printf_log + +static void debug_errors(void) +{ + unsigned long errCode; + + while((errCode = ERR_get_error())) { + char *err = ERR_error_string(errCode, NULL); + DEBUG("EAP-FAST error in OpenSSL - %s", err); + } +} + +// 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())) { + debug_errors(); + return -1; + }; + + /* Initialise the encryption operation. */ + if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) { + debug_errors(); + return -1; + }; + + /* 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)) { + debug_errors(); + return -1; + }; + + /* Initialise key and IV */ + if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) { + debug_errors(); + return -1; + }; + + /* Provide any AAD data. This can be called zero or more times as + * required + */ + if (1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len)) { + debug_errors(); + return -1; + }; + + /* 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)) { + debug_errors(); + return -1; + }; + 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)) { + debug_errors(); + return -1; + }; + ciphertext_len += len; + + /* Get the tag */ + if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)) { + debug_errors(); + return -1; + }; + + /* 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())) { + debug_errors(); + return -1; + }; + + /* Initialise the decryption operation. */ + if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) { + debug_errors(); + return -1; + }; + + /* 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)) { + debug_errors(); + return -1; + }; + + /* Initialise key and IV */ + if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) { + debug_errors(); + return -1; + }; + + /* Provide any AAD data. This can be called zero or more times as + * required + */ + if (!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len)) { + debug_errors(); + return -1; + }; + + /* 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)) { + debug_errors(); + return -1; + }; + 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)) { + debug_errors(); + return -1; + }; + } + + /* 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) return -1; + + /* Success */ + plaintext_len += len; + return plaintext_len; +} 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 index 0000000..d00e9a2 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.h @@ -0,0 +1,39 @@ +/* + * eap_fast_crypto.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_CRYPTO_H +#define _EAP_FAST_CRYPTO_H + +RCSIDH(eap_fast_crypto_h, "$Id$") + + +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); + +#endif /* _EAP_FAST_CRYPTO_H */ 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 index 0000000..093dc86 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_fast/rlm_eap_fast.c @@ -0,0 +1,659 @@ +/* + * 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. + char const *cipher_list; //!< cipher list specific to EAP-FAST + 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}, + { "cipher_list", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_fast_t, cipher_list) , 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; + } + + if (!inst->pac_lifetime) { + ERROR("rlm_eap_fast.pac_lifetime: must be non-zero"); + return -1; + } + +#ifdef TLS1_3_VERSION + if (inst->tls_conf->min_version == TLS1_3_VERSION) { + ERROR("There are no standards for using TLS 1.3 with EAP-FAST."); + ERROR("You MUST enable TLS 1.2 for EAP-FAST to work."); + return -1; + } + + if ((inst->tls_conf->max_version == TLS1_3_VERSION) || + (inst->tls_conf->min_version == TLS1_3_VERSION)) { + WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + WARN("!! There is no standard for using EAP-FAST with TLS 1.3"); + WARN("!! Please set tls_max_version = \"1.2\""); + WARN("!! FreeRADIUS only supports TLS 1.3 for special builds of wpa_supplicant and Windows"); + WARN("!! This limitation is likely to change in late 2021."); + WARN("!! If you are using this version of FreeRADIUS after 2021, you will probably need to upgrade"); + WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + } +#endif + + 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() +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +static int _session_secret(SSL *s, void *secret, int *secret_len, + UNUSED STACK_OF(SSL_CIPHER) *peer_ciphers, + UNUSED SSL_CIPHER **cipher, void *arg) +#else +static int _session_secret(SSL *s, void *secret, int *secret_len, + UNUSED STACK_OF(SSL_CIPHER) *peer_ciphers, + UNUSED const SSL_CIPHER **cipher, void *arg) +#endif +{ + // 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 client_random[SSL3_RANDOM_SIZE]; + uint8_t 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; + int 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 < (int) (length + sizeof(opaque->hdr))) { + 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 < 0) { + 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 + time(NULL); + t->pac.expired = false; + 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; + int ret = 0; + 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 { + RDEBUG3("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } + + /* + * Make request available to any SSL callbacks + */ + SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, request); + 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: + ret = 1; + goto done; + + /* + * Handshake is done, proceed with decoding tunneled + * data. + */ + case FR_TLS_OK: + break; + + /* + * Anything else: fail. + */ + default: + ret = 0; + goto done; + } + + /* + * 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); + ret = 0; + goto done; + + /* + * 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); + ret = 1; + goto done; + + /* + * Success: Automatically return MPPE keys. + */ + case PW_CODE_ACCESS_ACCEPT: + 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"); + } + ret = eaptls_success(handler, EAP_FAST_VERSION); + goto done; + + /* + * 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 + ret = 1; + goto done; + + default: + break; + } + + /* + * Something we don't understand: Reject it. + */ + eaptls_fail(handler, EAP_FAST_VERSION); + +done: + SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, NULL); + + return ret; +} + +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; + } + + /* + * Don't allow TLS 1.3 for us, even if it's allowed + * elsewhere. We haven't implemented the necessary + * changes, so we don't allow it. + */ + handler->opaque = tls_session = eaptls_session(handler, inst->tls_conf, client_cert, false); + + if (!tls_session) return 0; + + if (inst->cipher_list) { + RDEBUG("Over-riding main cipher list with '%s'", inst->cipher_list); + + if (!SSL_set_cipher_list(tls_session->ssl, inst->cipher_list)) { + REDEBUG("Failed over-riding cipher list to '%s'. EAP-FAST will likely not work", + inst->cipher_list); + } + } + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) + { + int i; + for (i = 0; ; i++) { + const char *cipher = SSL_get_cipher_list(tls_session->ssl, i); + if (!cipher) break; + if (!strstr(cipher, "ADH-")) continue; + RDEBUG("Setting security level to 0 to allow anonymous cipher suites"); + SSL_set_security_level(tls_session->ssl, 0); + break; + } + } +#endif + +#ifdef SSL_OP_NO_TLSv1_3 + /* + * Forcibly disable TLSv1.3 + * + * TLSv1.3 does not support opaque session tickets, which + * are needed for EAP-FAST. + */ + SSL_set_options(tls_session->ssl, SSL_OP_NO_TLSv1_3); +#endif + + /* + * 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) { + error: + 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"); + goto error; + } + + 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 */ +}; diff --git a/src/modules/rlm_eap/types/rlm_eap_gtc/all.mk b/src/modules/rlm_eap/types/rlm_eap_gtc/all.mk new file mode 100644 index 0000000..26f2eb0 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_gtc/all.mk @@ -0,0 +1,12 @@ +TARGETNAME := rlm_eap_gtc + +ifneq "$(TARGETNAME)" "" +TARGET := $(TARGETNAME).a +endif + +SOURCES := $(TARGETNAME).c + +SRC_CFLAGS := +TGT_LDLIBS := +SRC_INCDIRS := ../../ ../../libeap/ +TGT_PREREQS := libfreeradius-eap.a diff --git a/src/modules/rlm_eap/types/rlm_eap_gtc/rlm_eap_gtc.c b/src/modules/rlm_eap/types/rlm_eap_gtc/rlm_eap_gtc.c new file mode 100644 index 0000000..031eba2 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_gtc/rlm_eap_gtc.c @@ -0,0 +1,250 @@ +/* + * rlm_eap_gtc.c Handles 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 2003,2006 The FreeRADIUS server project + */ + +RCSID("$Id$") + +#include <stdio.h> +#include <stdlib.h> + +#include "eap.h" + +#include <freeradius-devel/rad_assert.h> + +/* + * EAP-GTC is just ASCII data carried inside of the EAP session. + * The length of the data is indicated by the encapsulating EAP + * protocol. + */ +typedef struct rlm_eap_gtc_t { + char const *challenge; + char const *auth_type_name; + int auth_type; +} rlm_eap_gtc_t; + +static CONF_PARSER module_config[] = { + { "challenge", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_gtc_t, challenge), "Password: " }, + { "auth_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_gtc_t, auth_type_name), "PAP" }, + CONF_PARSER_TERMINATOR +}; + + + +/* + * Attach the module. + */ +static int mod_instantiate(CONF_SECTION *cs, void **instance) +{ + rlm_eap_gtc_t *inst; + DICT_VALUE *dval; + + *instance = inst = talloc_zero(cs, rlm_eap_gtc_t); + if (!inst) return -1; + + /* + * Parse the configuration attributes. + */ + if (cf_section_parse(cs, inst, module_config) < 0) { + return -1; + } + + if (inst->auth_type_name && *inst->auth_type_name) { + dval = dict_valbyname(PW_AUTH_TYPE, 0, inst->auth_type_name); + if (!dval) { + ERROR("rlm_eap_gtc: Unknown Auth-Type %s", + inst->auth_type_name); + return -1; + } + + inst->auth_type = dval->value; + } else { + inst->auth_type = PW_AUTH_TYPE_LOCAL; + } + return 0; +} + +/* + * Initiate the EAP-GTC session by sending a challenge to the peer. + */ +static int mod_session_init(void *instance, eap_handler_t *handler) +{ + char challenge_str[1024]; + int length; + EAP_DS *eap_ds = handler->eap_ds; + rlm_eap_gtc_t *inst = (rlm_eap_gtc_t *) instance; + + if (radius_xlat(challenge_str, sizeof(challenge_str), handler->request, inst->challenge, NULL, NULL) < 0) { + return 0; + } + + length = strlen(challenge_str); + + /* + * We're sending a request... + */ + eap_ds->request->code = PW_EAP_REQUEST; + + eap_ds->request->type.data = talloc_array(eap_ds->request, + uint8_t, length); + if (!eap_ds->request->type.data) { + return 0; + } + + memcpy(eap_ds->request->type.data, challenge_str, length); + eap_ds->request->type.length = length; + + /* + * We don't need to authorize the user at this point. + * + * We also don't need to keep the challenge, as it's + * stored in 'handler->eap_ds', which will be given back + * to us... + */ + handler->stage = PROCESS; + + return 1; +} + + +/* + * Authenticate a previously sent challenge. + */ +static int CC_HINT(nonnull) mod_process(void *instance, eap_handler_t *handler) +{ + VALUE_PAIR *vp; + EAP_DS *eap_ds = handler->eap_ds; + rlm_eap_gtc_t *inst = (rlm_eap_gtc_t *) instance; + REQUEST *request = handler->request; + + /* + * Get the Cleartext-Password for this user. + */ + rad_assert(handler->stage == PROCESS); + + /* + * Sanity check the response. We need at least one byte + * of data. + */ + if (eap_ds->response->length <= 4) { + ERROR("rlm_eap_gtc: corrupted data"); + eap_ds->request->code = PW_EAP_FAILURE; + return 0; + } + +#if 0 + if ((rad_debug_lvl > 2) && fr_log_fp) { + int i; + + for (i = 0; i < eap_ds->response->length - 4; i++) { + if ((i & 0x0f) == 0) fprintf(fr_log_fp, "%d: ", i); + + fprintf(fr_log_fp, "%02x ", eap_ds->response->type.data[i]); + + if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n"); + } + } +#endif + + /* + * Handle passwords here. + */ + if (inst->auth_type == PW_AUTH_TYPE_LOCAL) { + /* + * For now, do cleartext password authentication. + */ + vp = fr_pair_find_by_num(request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY); + if (!vp) { + REDEBUG2("Cleartext-Password is required for authentication"); + eap_ds->request->code = PW_EAP_FAILURE; + return 0; + } + + if (eap_ds->response->type.length != vp->vp_length) { + REDEBUG2("Passwords are of different length. %u %u", (unsigned) eap_ds->response->type.length, (unsigned) vp->vp_length); + eap_ds->request->code = PW_EAP_FAILURE; + return 0; + } + + if (memcmp(eap_ds->response->type.data, + vp->vp_strvalue, vp->vp_length) != 0) { + REDEBUG2("Passwords are different"); + eap_ds->request->code = PW_EAP_FAILURE; + return 0; + } + + /* + * EAP packets can be ~64k long maximum, and + * we don't like that. + */ + } else if (eap_ds->response->type.length <= 128) { + int rcode; + + /* + * If there was a User-Password in the request, + * why the heck are they using EAP-GTC? + */ + fr_pair_delete_by_num(&request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY); + + vp = pair_make_request("User-Password", NULL, T_OP_EQ); + if (!vp) { + return 0; + } + + fr_pair_value_bstrncpy(vp, eap_ds->response->type.data, eap_ds->response->type.length); + + /* + * Add the password to the request, and allow + * another module to do the work of authenticating it. + */ + request->password = vp; + + /* + * This is a wild & crazy hack. + */ + rcode = process_authenticate(inst->auth_type, request); + if (rcode != RLM_MODULE_OK) { + eap_ds->request->code = PW_EAP_FAILURE; + return 0; + } + + } else { + ERROR("rlm_eap_gtc: Response is too large to understand"); + eap_ds->request->code = PW_EAP_FAILURE; + return 0; + + } + + eap_ds->request->code = PW_EAP_SUCCESS; + + 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_gtc; +rlm_eap_module_t rlm_eap_gtc = { + .name = "eap_gtc", + .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 */ +}; diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/.gitignore b/src/modules/rlm_eap/types/rlm_eap_ikev2/.gitignore new file mode 100644 index 0000000..01a5daa --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/.gitignore @@ -0,0 +1 @@ +all.mk diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/all.mk.in b/src/modules/rlm_eap/types/rlm_eap_ikev2/all.mk.in new file mode 100644 index 0000000..40ba9e7 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/all.mk.in @@ -0,0 +1,13 @@ +TARGETNAME := @targetname@ + +ifneq "$(TARGETNAME)" "" +TARGET := $(TARGETNAME).a +endif + +SOURCES := $(TARGETNAME).c logging_impl.c ike_conf.c + +SRC_CFLAGS := @mod_cflags@ +TGT_LDLIBS := @mod_cflags@ +TGT_LDLIBS += $(LIBS) +SRC_INCDIRS := ../../ ../../libeap/ +TGT_PREREQS := libfreeradius-eap.a diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/configure b/src/modules/rlm_eap/types/rlm_eap_ikev2/configure new file mode 100755 index 0000000..2c75b54 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/configure @@ -0,0 +1,4149 @@ +#! /bin/sh +# From configure.ac Revision. +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="rlm_eap_ikev2.c" +ac_subst_vars='LTLIBOBJS +LIBOBJS +targetname +mod_cflags +mod_ldflags +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +runstatedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_rlm_eap_ikev2 +with_eap_ikev2_include_dir +with_eap_ikev2_lib_dir +with_eap_ikev2_dir +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir runstatedir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --without-rlm_eap_ikev2 build without rlm_eap_ikev2 + --with-eap-ikev2-include-dir=DIR + Directory where the eap-ikev2 includes may be found + --with-eap-ikev2-lib-dir=DIR + Directory where the eap-ikev2 libraries may be found + --with-eap-ikev2-dir=DIR + Base directory where eap-ikev2 is installed + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + +# Check whether --with-rlm_eap_ikev2 was given. +if test "${with_rlm_eap_ikev2+set}" = set; then : + withval=$with_rlm_eap_ikev2; +fi + + + +if test x$with_rlm_eap_ikev2 != xno; then + eap_ikev2_include_dir= + +# Check whether --with-eap-ikev2-include-dir was given. +if test "${with_eap_ikev2_include_dir+set}" = set; then : + withval=$with_eap_ikev2_include_dir; case "$withval" in + no) + as_fn_error $? "Need eap-ikev2-include-dir" "$LINENO" 5 + ;; + yes) + ;; + *) + eap_ikev2_include_dir="$withval" + ;; + esac +fi + + + eap_ikev2_lib_dir= + +# Check whether --with-eap-ikev2-lib-dir was given. +if test "${with_eap_ikev2_lib_dir+set}" = set; then : + withval=$with_eap_ikev2_lib_dir; case "$withval" in + no) + as_fn_error $? "Need eap-ikev2-lib-dir" "$LINENO" 5 + ;; + yes) + ;; + *) + eap_ikev2_lib_dir="$withval" + ;; + esac +fi + + + +# Check whether --with-eap-ikev2-dir was given. +if test "${with_eap_ikev2_dir+set}" = set; then : + withval=$with_eap_ikev2_dir; case "$withval" in + no) + as_fn_error $? "Need eap-ikev2-dir" "$LINENO" 5 + ;; + yes) + ;; + *) + eap_ikev2_lib_dir="$withval/lib" + eap_ikev2_include_dir="$withval/include" + ;; + esac +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL support" >&5 +$as_echo_n "checking for OpenSSL support... " >&6; } + if test "x$OPENSSL_LIBS" != "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fail="OpenSSL" + fi + + smart_try_dir="$eap_ikev2_include_dir" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + +ac_safe=`echo "EAPIKEv2/connector.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 EAPIKEv2/connector.h in $try" >&5 +$as_echo_n "checking for EAPIKEv2/connector.h in $try... " >&6; } + CPPFLAGS="-isystem $try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <EAPIKEv2/connector.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}/EAPIKEv2/connector.h" >&5 +$as_echo_n "checking for ${_prefix}/EAPIKEv2/connector.h... " >&6; } + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <EAPIKEv2/connector.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 EAPIKEv2/connector.h" >&5 +$as_echo_n "checking for EAPIKEv2/connector.h... " >&6; } + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <EAPIKEv2/connector.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 try in $_smart_include_dir; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EAPIKEv2/connector.h in $try" >&5 +$as_echo_n "checking for EAPIKEv2/connector.h in $try... " >&6; } + CPPFLAGS="-isystem $try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <EAPIKEv2/connector.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_EAPIKEv2_connector_h" != "xyes"; then + fail="$fail EAPIKEv2/connector.h" + fi + + + LIBS="${OPENSSL_LIBS}" + smart_try_dir="$eap_ikev2_lib_dir" + + +sm_lib_safe=`echo "eap-ikev2" | sed 'y%./+-%__p_%'` +sm_func_safe=`echo "ikev2_set_log_callback" | sed 'y%./+-%__p_%'` + +old_LIBS="$LIBS" +old_CPPFLAGS="$CPPFLAGS" +smart_lib= +smart_ldflags= +smart_lib_dir= + +if test "x$smart_try_dir" != "x"; then + for try in $smart_try_dir; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ikev2_set_log_callback in -leap-ikev2 in $try" >&5 +$as_echo_n "checking for ikev2_set_log_callback in -leap-ikev2 in $try... " >&6; } + LIBS="-leap-ikev2 $old_LIBS" + CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char ikev2_set_log_callback(); +int +main () +{ +ikev2_set_log_callback() + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + smart_lib="-leap-ikev2" + smart_ldflags="-L$try -Wl,-rpath,$try" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + break + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + LIBS="$old_LIBS" + CPPFLAGS="$old_CPPFLAGS" +fi + +if test "x$smart_lib" = "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ikev2_set_log_callback in -leap-ikev2" >&5 +$as_echo_n "checking for ikev2_set_log_callback in -leap-ikev2... " >&6; } + LIBS="-leap-ikev2 $old_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char ikev2_set_log_callback(); +int +main () +{ +ikev2_set_log_callback() + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + smart_lib="-leap-ikev2" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$old_LIBS" +fi + +if test "x$smart_lib" = "x"; then + for try in /usr/local/lib /opt/lib; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ikev2_set_log_callback in -leap-ikev2 in $try" >&5 +$as_echo_n "checking for ikev2_set_log_callback in -leap-ikev2 in $try... " >&6; } + LIBS="-leap-ikev2 $old_LIBS" + CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char ikev2_set_log_callback(); +int +main () +{ +ikev2_set_log_callback() + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + smart_lib="-leap-ikev2" + smart_ldflags="-L$try -Wl,-rpath,$try" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + break + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + LIBS="$old_LIBS" + CPPFLAGS="$old_CPPFLAGS" +fi + +if test "x$smart_lib" != "x"; then + eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes" + LIBS="$smart_ldflags $smart_lib $old_LIBS" + SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS" +fi + + if test "x$ac_cv_lib_eap_ikev2_ikev2_set_log_callback" != "xyes"; then + fail="$fail libeap-ikev2" + fi + + targetname=rlm_eap_ikev2 # keep this! Don't change! +else + targetname= # keep this! Don't change! + echo \*\*\* module rlm_eap_ikev2 is disabled. # keep this! Don't change! +fi + +if test x"$fail" != x""; then + if test x"${enable_strict_dependencies}" = x"yes"; then + as_fn_error $? "set --without-rlm_eap_ikev2 to disable it explicitly." "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_eap_ikev2." >&5 +$as_echo "$as_me: WARNING: silently not building rlm_eap_ikev2." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_eap_ikev2 requires: $fail." >&5 +$as_echo "$as_me: WARNING: FAILURE: rlm_eap_ikev2 requires: $fail." >&2;}; + targetname="" + fi +fi + +mod_ldfags="$SMART_LIBS" +mod_cflags="$SMART_CPPFLAGS" + + + + + # keep this! Don't change! +ac_config_files="$ac_config_files all.mk" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + # keep this! Don't change! diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/configure.ac b/src/modules/rlm_eap/types/rlm_eap_ikev2/configure.ac new file mode 100644 index 0000000..b922204 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/configure.ac @@ -0,0 +1,111 @@ +AC_PREREQ([2.68]) +AC_INIT(rlm_eap_ikev2.c) +AC_REVISION($Revision$) +FR_INIT_MODULE([rlm_eap_ikev2]) + +if test x$with_[]modname != xno; then + dnl extra argument: --with-eap-ikev2-include-dir=DIR + eap_ikev2_include_dir= + AC_ARG_WITH(eap-ikev2-include-dir, + [AS_HELP_STRING([--with-eap-ikev2-include-dir=DIR], + [Directory where the eap-ikev2 includes may be found])], + [case "$withval" in + no) + AC_MSG_ERROR(Need eap-ikev2-include-dir) + ;; + yes) + ;; + *) + eap_ikev2_include_dir="$withval" + ;; + esac]) + + dnl extra argument: --with-eap-ikev2-lib-dir=DIR + eap_ikev2_lib_dir= + AC_ARG_WITH(eap-ikev2-lib-dir, + [AS_HELP_STRING([--with-eap-ikev2-lib-dir=DIR], + [Directory where the eap-ikev2 libraries may be found])], + [case "$withval" in + no) + AC_MSG_ERROR(Need eap-ikev2-lib-dir) + ;; + yes) + ;; + *) + eap_ikev2_lib_dir="$withval" + ;; + esac]) + + dnl extra argument: --with-eap-ikev2-dir=DIR + AC_ARG_WITH(eap-ikev2-dir, + [AS_HELP_STRING([--with-eap-ikev2-dir=DIR], + [Base directory where eap-ikev2 is installed])], + [case "$withval" in + no) + AC_MSG_ERROR(Need eap-ikev2-dir) + ;; + yes) + ;; + *) + eap_ikev2_lib_dir="$withval/lib" + eap_ikev2_include_dir="$withval/include" + ;; + esac]) + + dnl ############################################################ + dnl # Check for OpenSSL support + dnl ############################################################ + + AC_MSG_CHECKING(for OpenSSL support) + if test "x$OPENSSL_LIBS" != "x"; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fail="OpenSSL" + fi + + dnl ############################################################ + dnl # Check for eap-ikev2 includes + dnl ############################################################ + smart_try_dir="$eap_ikev2_include_dir" + FR_SMART_CHECK_INCLUDE([EAPIKEv2/connector.h]) + if test "x$ac_cv_header_EAPIKEv2_connector_h" != "xyes"; then + fail="$fail EAPIKEv2/connector.h" + fi + + dnl ############################################################ + dnl # Check for eap-ikev2 library + dnl ############################################################ + + LIBS="${OPENSSL_LIBS}" + smart_try_dir="$eap_ikev2_lib_dir" + FR_SMART_CHECK_LIB([eap-ikev2],[ikev2_set_log_callback]) + if test "x$ac_cv_lib_eap_ikev2_ikev2_set_log_callback" != "xyes"; then + fail="$fail libeap-ikev2" + fi + + targetname=modname # keep this! Don't change! +else + targetname= # keep this! Don't change! + echo \*\*\* module modname is disabled. # keep this! Don't change! +fi + +dnl Don't change this section. +if test x"$fail" != x""; then + if test x"${enable_strict_dependencies}" = x"yes"; then + AC_MSG_ERROR([set --without-]modname[ to disable it explicitly.]) + else + AC_MSG_WARN([silently not building ]modname[.]) + AC_MSG_WARN([FAILURE: ]modname[ requires: $fail.]); + targetname="" + fi +fi + +mod_ldfags="$SMART_LIBS" +mod_cflags="$SMART_CPPFLAGS" + +AC_SUBST(mod_ldflags) +AC_SUBST(mod_cflags) + +AC_SUBST(targetname) # keep this! Don't change! +AC_OUTPUT(all.mk) # keep this! Don't change! diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/ike_conf.c b/src/modules/rlm_eap/types/rlm_eap_ikev2/ike_conf.c new file mode 100644 index 0000000..dda4f67 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/ike_conf.c @@ -0,0 +1,420 @@ +/* + * ike_conf.c - module config loading functions + * + * This file is part of rlm_eap_ikev2 freeRADIUS module which implements + * EAP-IKEv2 protocol functionality. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2005-2006 Krzysztof Rzecki <krzysztof.rzecki@ccns.pl> + * Copyright (C) 2005-2006 Rafal Mijal <rafal.mijal@ccns.pl> + * Copyright (C) 2005-2006 Piotr Marnik <piotr.marnik@ccns.pl> + * Copyright (C) 2005-2006 Pawel Matejski <pawel.matejski@ccns.pl> + * Copyright 1999-2007 The FreeRADIUS server project + * + */ + +#include <freeradius-devel/radiusd.h> +#include <freeradius-devel/rad_assert.h> + +#include "ike_conf.h" +#include "eap.h" +#include "logging_impl.h" + +static int rad_load_transforms(struct Protocol *prot,CONF_SECTION *cf); + +struct config_transform +{ + char const *name; + u_int8_t type; + int exist_flag; +}; + +enum { + OPT_INTEGRITY = 0x01, + OPT_PRF = 0x02, + OPT_ENCRYPTION = 0x04, + OPT_DHGROUP = 0x08, + OPT_NEEDED = OPT_INTEGRITY | OPT_PRF | OPT_ENCRYPTION | OPT_DHGROUP + +}; + +static struct config_transform config_transforms[] = +{ + {"integrity", IKEv2_TRT_INTEGRITY_ALGORITHM, OPT_INTEGRITY}, + {"prf", IKEv2_TRT_PSEUDO_RANDOM_FUNCTION, OPT_PRF}, + {"encryption", IKEv2_TRT_ENCRYPTION_ALGORITHM, OPT_ENCRYPTION}, + {"dhgroup", IKEv2_TRT_DIFFIE_HELLMAN_GROUP, OPT_DHGROUP }, + {NULL, 0, 0} /* end of list */ + +}; + +/* + * Copied from rlm_files, and NOT under the same copyright + * as the rest of the module! + * + * Also, it is UNNECESSARY to read the "users" file here! + * Doing this shows a misunderstanding of how the server works. + */ +int getusersfile(TALLOC_CTX *ctx, char const *filename, PAIR_LIST **pair_list, char const *compat_mode_str) +{ + int rcode; + PAIR_LIST *users = NULL; + + rcode = pairlist_read(ctx, filename, &users, 1); + if (rcode < 0) { + return -1; + } + + /* + * Walk through the 'users' file list, if we're debugging, + * or if we're in compat_mode. + */ + if ((rad_debug_lvl) || + (strcmp(compat_mode_str, "cistron") == 0)) { + PAIR_LIST *entry; + VALUE_PAIR *vp; + bool compat_mode = false; + + if (strcmp(compat_mode_str, "cistron") == 0) { + compat_mode = true; + } + + entry = users; + while (entry) { + if (compat_mode) { + DEBUG("[%s]:%d Cistron compatibility checks for entry %s ...", + filename, entry->lineno, + entry->name); + } + + /* + * Look for improper use of '=' in the + * check items. They should be using + * '==' for on-the-wire RADIUS attributes, + * and probably ':=' for server + * configuration items. + */ + for (vp = entry->check; vp != NULL; vp = vp->next) { + /* + * Ignore attributes which are set + * properly. + */ + if (vp->op != T_OP_EQ) { + continue; + } + + /* + * If it's a vendor attribute, + * or it's a wire protocol, + * ensure it has '=='. + */ + if ((vp->da->vendor!= 0) || + (vp->da->attr < 0x100)) { + if (!compat_mode) { + WARN("[%s]:%d Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for user %s", + filename, entry->lineno, + vp->da->name, vp->da->name, + entry->name); + } else { + DEBUG("\tChanging '%s =' to '%s =='", + vp->da->name, vp->da->name); + } + vp->op = T_OP_CMP_EQ; + continue; + } + + /* + * Cistron Compatibility mode. + * + * Re-write selected attributes + * to be '+=', instead of '='. + * + * All others get set to '==' + */ + if (compat_mode) { + /* + * Non-wire attributes become += + * + * On the write attributes + * become == + */ + if ((vp->da->attr >= 0x100) && + (vp->da->attr <= 0xffff) && + (vp->da->attr != PW_HINT) && + (vp->da->attr != PW_HUNTGROUP_NAME)) { + DEBUG("\tChanging '%s =' to '%s +='", + vp->da->name, vp->da->name); + vp->op = T_OP_ADD; + } else { + DEBUG("\tChanging '%s =' to '%s =='", + vp->da->name, vp->da->name); + vp->op = T_OP_CMP_EQ; + } + } + + } /* end of loop over check items */ + + + /* + * Look for server configuration items + * in the reply list. + * + * It's a common enough mistake, that it's + * worth doing. + */ + for (vp = entry->reply; vp != NULL; vp = vp->next) { + /* + * If it's NOT a vendor attribute, + * and it's NOT a wire protocol + * and we ignore Fall-Through, + * then bitch about it, giving a + * good warning message. + */ + if ((vp->da->vendor == 0) && + (vp->da->attr > 1000)) { + WARN("[%s]:%d Check item \"%s\"\n" + "\tfound in reply item list for user \"%s\".\n" + "\tThis attribute MUST go on the first line" + " with the other check items", + filename, entry->lineno, vp->da->name, entry->name); + } + } + + entry = entry->next; + } + } + + *pair_list = users; + return 0; +} + +/** + * Load all proposals from 'propsals' subsection + */ + +int rad_load_proposals(ikev2_ctx *i2,CONF_SECTION *cf) +{ + rad_assert(i2!=NULL && cf!=NULL); + + CONF_SECTION *cf_prop=NULL; + cf=cf_subsection_find_next(cf,NULL,"proposals"); + if(!cf) { + ERROR(IKEv2_LOG_PREFIX "Can't find proposals section"); + return -1; + } + int nprop=0; + for( + cf_prop=cf_subsection_find_next(cf,NULL,"proposal"); + cf_prop; + cf_prop=cf_subsection_find_next(cf,cf_prop,"proposal") + ) { + nprop++; + struct Proposal *prop; + struct Protocol *prot; + prop=AddProposal(&i2->suppProp); + prot=AddProtocol(prop,IKEv2_PID_IKE_SA,0,0); + if(rad_load_transforms(prot,cf_prop)) { + ERROR(IKEv2_LOG_PREFIX "Failed to load proposal (%d)", + nprop); + return -1; + } + } + if(!nprop) { + ERROR(IKEv2_LOG_PREFIX "Can't find any proposal"); + return -1; + } + return 0; + +} + + + +/** + * Load transforms from protocol subsection + */ + +static int rad_load_transforms(struct Protocol *prot, CONF_SECTION *cf) +{ + CONF_PAIR *cp; + int option_exists = 0; + int i = 0; + + rad_assert(prot); + rad_assert(cf); + + DEBUG(IKEv2_LOG_PREFIX "Begin load transforms"); + + while(config_transforms[i].name) + { + uint8_t id; + uint16_t keylen; + + for(cp = cf_pair_find(cf,config_transforms[i].name); + cp; + cp = cf_pair_find_next(cf,cp,config_transforms[i].name)) { + if (TransformFromName(cf_pair_value(cp),config_transforms[i].type,&id,&keylen)) { + ERROR(IKEv2_LOG_PREFIX "Unsupported %s transform: %s ", + config_transforms[i].name,cf_pair_value(cp)); + return -1; + } + + if (!AddTransform(prot,config_transforms[i].type,id,keylen)) { + ERROR(IKEv2_LOG_PREFIX "Problem with transform %s:%s", + config_transforms[i].name,cf_pair_value(cp)); + return -1; + } + option_exists |= config_transforms[i].exist_flag; + } + i++; + } + + if ((option_exists & OPT_NEEDED) != OPT_NEEDED) { + ERROR(IKEv2_LOG_PREFIX "Not all mandatory transforms are set properly"); + DEBUG(IKEv2_LOG_PREFIX "Option flags: 0x%02X",option_exists); + + return -1; + } + return 0; +} + + +void rad_update_shared_seclist(struct sharedSecList **list, char const *id, VALUE_PAIR *items, + int default_client_authtype) +{ + rad_assert(list && id); + + char *ike_id; + char *secret = NULL; + int id_type = 0; + int authtype = default_client_authtype; + VALUE_PAIR *vp; + + memcpy(&ike_id, &id, sizeof(id)); + + if (!items) { + AddSharedSec(list, 0, ike_id, NULL, default_client_authtype); + + return; + } + + //idtype + vp = fr_pair_find_by_num(items, RAD_EAP_IKEV2_IDTYPE, 0, TAG_ANY); + if (!vp) { + DEBUG(IKEv2_LOG_PREFIX "[%s] -- Id type not set", id); + } else { + id_type = vp->vp_integer; + if (!id_type) { + DEBUG(IKEv2_LOG_PREFIX "[%s] -- Not valid id type", id); + } + } + + //secret + vp = fr_pair_find_by_num(items, RAD_EAP_IKEV2_SECRET, 0, TAG_ANY); + if (!vp || !vp->vp_length) { + DEBUG(IKEv2_LOG_PREFIX "[%s] -- Secret not set", id); + } else { + memcpy(&secret, &vp->vp_strvalue, sizeof(secret)); + } + + //authtype + vp = fr_pair_find_by_num(items, RAD_EAP_IKEV2_AUTHTYPE, 0, TAG_ANY); + if (vp && vp->vp_length) { + authtype = AuthtypeFromName(vp->vp_strvalue); + + if (authtype == -1) { + ERROR(IKEv2_LOG_PREFIX "Unsupported 'EAP-IKEv2-AuthType' value (%s),using 'both'", + vp->vp_strvalue); + authtype = IKEv2_AUTH_BOTH; + } + + } + + AddSharedSec(list, id_type, ike_id, secret, authtype); +} + +/** + * load user credentials from raddb/users (read directly from users file) + */ + +int rad_load_credentials(TALLOC_CTX *ctx, ikev2_ctx *i2,char *filename,char *authtype_name) +{ + rad_assert(i2 && filename && authtype_name); + int authtype; + + authtype=AuthtypeFromName(authtype_name); + if(authtype==-1) { + ERROR(IKEv2_LOG_PREFIX "Unsupported 'default_auth_type' value (%s), using both",authtype_name); + authtype=IKEv2_AUTH_BOTH; + } + + PAIR_LIST *users=NULL; + if(getusersfile(ctx, filename,&users,"no")!=0) { + ERROR(IKEv2_LOG_PREFIX "Error while loading %s userfile",filename); + return -1; + } + PAIR_LIST *tusers=users; + while(tusers) { + if(strcmp(tusers->name,"DEFAULT")) { + rad_update_shared_seclist(&i2->sslist,tusers->name,tusers->check,authtype); + } + tusers=tusers->next; + } + pairlist_free(&users); + //print sslist +// struct sharedSecList *sslist=i2->sslist; +// while(sslist) { +// ERROR("sslist:id=%s",sslist->id); +// ERROR("sslist:idlen=%d",sslist->idlen); +// ERROR("sslist:pwd=%s",sslist->pwd); +// ERROR("sslist:pwdlen=%d",sslist->pwdlen); +// ERROR("sslist:idtype= %d",sslist->idtype); +// ERROR("sslist:authtype=%d",sslist->authtype); +// sslist=sslist->next; +// } + return 0; + + +} + +int rad_get_authtype(char* authtype_name) +{ + rad_assert(authtype_name); + if(!strcmp(authtype_name,"cert")) { + DEBUG(IKEv2_LOG_PREFIX "Using server auth type: cert"); + return IKEv2_AUTH_CERT; + } + if(!strcmp(authtype_name,"secret")) { + DEBUG(IKEv2_LOG_PREFIX "Using server auth type: secret"); + return IKEv2_AUTH_SK; + } + AUTH(IKEv2_LOG_PREFIX "Unsupported server auth type: %s",authtype_name); + AUTH(IKEv2_LOG_PREFIX "Using server auth type: secret (default)"); + return IKEv2_AUTH_SK; +} + +int file_exists(char *filename) +{ + int result=0; + FILE *fp=fopen(filename,"r"); + if(fp) { + result=1; + fclose(fp); + } + return result; +} + + + diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/ike_conf.h b/src/modules/rlm_eap/types/rlm_eap_ikev2/ike_conf.h new file mode 100644 index 0000000..ee2561c --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/ike_conf.h @@ -0,0 +1,48 @@ +/* + * ike_conf.h - module config loading functions + * + * This file is part of rlm_eap_ikev2 freeRADIUS module which implements + * EAP-IKEv2 protocol functionality. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2005-2006 Krzysztof Rzecki <krzysztof.rzecki@ccns.pl> + * Copyright (C) 2005-2006 Rafal Mijal <rafal.mijal@ccns.pl> + * Copyright (C) 2005-2006 Piotr Marnik <piotr.marnik@ccns.pl> + * Copyright (C) 2005-2006 Pawel Matejski <pawel.matejski@ccns.pl> + * + */ + +#ifndef IKE_CONF_H +#define IKE_CONF_H + +#include <EAPIKEv2/connector.h> +#include "eap.h" + +#define RAD_EAP_IKEV2_IDTYPE 1103 +#define RAD_EAP_IKEV2_ID 1104 +#define RAD_EAP_IKEV2_SECRET 1105 +#define RAD_EAP_IKEV2_AUTHTYPE 1106 + + +int rad_load_proposals(ikev2_ctx *i2,CONF_SECTION *cf); +int rad_load_credentials(TALLOC_CTX *ctx, ikev2_ctx *i2,char *filename,char *authtype_name); +int getusersfile(TALLOC_CTX *ctx, char const *filename, PAIR_LIST **pair_list,char const *compat_mode_str); +void rad_update_shared_seclist(struct sharedSecList **list, char const *id, VALUE_PAIR *items, + int default_client_authtype); +int rad_get_authtype(char *authtype_name); +int rad_get_client_authtype(char const *authtype); +int file_exists(char *filename); +#endif //IKE_CONF_H diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/logging_impl.c b/src/modules/rlm_eap/types/rlm_eap_ikev2/logging_impl.c new file mode 100644 index 0000000..d618b6f --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/logging_impl.c @@ -0,0 +1,52 @@ +/* + * logging_impl.c - logging callback for lib-eapikev2 + * + * This file is part of rlm_eap_ikev2 freeRADIUS module which implements + * EAP-IKEv2 protocol functionality. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2005-2006 Krzysztof Rzecki <krzysztof.rzecki@ccns.pl> + * Copyright (C) 2005-2006 Rafal Mijal <rafal.mijal@ccns.pl> + * Copyright (C) 2005-2006 Piotr Marnik <piotr.marnik@ccns.pl> + * Copyright (C) 2005-2006 Pawel Matejski <pawel.matejski@ccns.pl> + * + */ + +#include <freeradius-devel/radiusd.h> +#include "logging_impl.h" +#include <stdio.h> +#include <stdlib.h> +#include <EAPIKEv2/logging.h> + +void vxlogf(int iklevel, char const * fmt,va_list ap) +{ + int level; + switch (iklevel) { + case I2L_DBG: + level=L_DBG; + break; + case I2L_INFO: + level=L_INFO; + break; + case I2L_ERR: + level=L_ERR; + break; + default: + level=L_DBG; + + } + vradlog(level, fmt, ap); +} diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/logging_impl.h b/src/modules/rlm_eap/types/rlm_eap_ikev2/logging_impl.h new file mode 100644 index 0000000..923cd04 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/logging_impl.h @@ -0,0 +1,35 @@ +/* + * logging_impl.c - logging callback for lib-eapikev2 + * + * This file is part of rlm_eap_ikev2 freeRADIUS module which implements + * EAP-IKEv2 protocol functionality. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2005-2006 Krzysztof Rzecki <krzysztof.rzecki@ccns.pl> + * Copyright (C) 2005-2006 Rafal Mijal <rafal.mijal@ccns.pl> + * Copyright (C) 2005-2006 Piotr Marnik <piotr.marnik@ccns.pl> + * Copyright (C) 2005-2006 Pawel Matejski <pawel.matejski@ccns.pl> + * + */ + +#ifndef LOGGING_IMPL_H +#define LOGGING_IMPL_H +#include <stdarg.h> + +#define IKEv2_LOG_PREFIX " rlm_eap_ikev2: " + +void CC_HINT(format (printf, 2, 0)) vxlogf(int iklevel, char const * fmt, va_list ap); +#endif //LOGGING_IMPL_H diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/rlm_eap_ikev2.c b/src/modules/rlm_eap/types/rlm_eap_ikev2/rlm_eap_ikev2.c new file mode 100644 index 0000000..9733632 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/rlm_eap_ikev2.c @@ -0,0 +1,526 @@ +/* + * rlm_eap_ikev2.c - Handles that are called from eap + * + * This file is part of rlm_eap_ikev2 freeRADIUS module which implements + * EAP-IKEv2 protocol functionality. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2005-2006 Krzysztof Rzecki <krzysztof.rzecki@ccns.pl> + * Copyright (C) 2005-2006 Rafal Mijal <rafal.mijal@ccns.pl> + * Copyright (C) 2005-2006 Piotr Marnik <piotr.marnik@ccns.pl> + * Copyright (C) 2005-2006 Pawel Matejski <pawel.matejski@ccns.pl> + * Copyright 1999-2007 The FreeRADIUS server project + * + */ + +#include <freeradius-devel/radiusd.h> +#include "eap.h" + +#include <assert.h> +#include <freeradius-devel/rad_assert.h> + +#include "logging_impl.h" +#include <EAPIKEv2/connector.h> +#include "ike_conf.h" + +typedef enum { + PW_IKEV2_CHALLENGE = 1, + PW_IKEV2_RESPONSE, + PW_IKEV2_SUCCESS, + PW_IKEV2_FAILURE, + PW_IKEV2_MAX_CODES +} pw_ikev2_code; + +#define IKEV2_HEADER_LEN 4 +#define IKEV2_MPPE_KEY_LEN 32 + +typedef struct rlm_eap_ikev2 { + char const *tls_ca_file; //!< Sets the full path to a CA certificate (used to validate + //!< the certificate the server presents). + + char const *tls_private_key_file; //!< Sets the path to the private key for our public + //!< certificate. + char const *tls_private_key_password; //!< Sets the path to the private key for our public + //!< certificate. + + char const *tls_certificate_file; //!< Sets the path to the public certificate file we present + //!< to the servers. + char const *tls_crl; + + char const *id; + uint32_t max_fragment_size; + uint32_t dh_counter_max; + + char const *default_auth_type; + char const *users_file_name; + char const *server_auth_type; + char const *server_id_type; + bool send_cert_request; + + uint32_t fast_expire; + + bool enable_fast_dhex; + bool enable_fast_reconnect; +} rlm_eap_ikev2_t; + +CONF_PARSER module_config[] = { + { "ca_file", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, tls_ca_file), NULL }, + { "private_key_file", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, tls_private_key_file), NULL }, + { "private_key_password", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, tls_private_key_password), NULL }, + { "certificate_file", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, tls_certificate_file), NULL }, + { "crl_file", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, tls_crl), NULL }, + + { "id", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, id), NULL }, + { "fragment_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_ikev2_t, max_fragment_size), IKEv2_DEFAULT_MAX_FRAGMENT_SIZE_STR }, + { "dh_counter_max", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_ikev2_t, dh_counter_max), IKEv2_DEFAULT_DH_COUNTER_MAX_STR }, + { "default_authtype", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, default_auth_type), "both" }, + { "usersfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_eap_ikev2_t, users_file_name),"${confdir}/users" }, + { "server_authtype", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, server_auth_type), "secret" }, + { "idtype", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, server_id_type), IKEv2_DEFAULT_IDTYPE_STR }, + { "certreq", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ikev2_t, send_cert_request), "no" }, + { "fast_timer_expire", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_ikev2_t, fast_expire), "900" }, + + { "fast_dh_exchange", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ikev2_t, enable_fast_dhex), "no" }, + { "enable_fast_reauth", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ikev2_t, enable_fast_reconnect), "yes" }, + CONF_PARSER_TERMINATOR +}; + +static int set_mppe_keys(eap_handler_t *handler) +{ + uint8_t const *p; + struct IKEv2Session *session; + + session = ((struct IKEv2Data*)handler->opaque)->session; + + if (session->eapKeyData==NULL){ + INFO(IKEv2_LOG_PREFIX "Key session not available!!!"); + return 1; + } + + p = session->eapKeyData; + eap_add_reply(handler->request, "MS-MPPE-Recv-Key", p, IKEV2_MPPE_KEY_LEN); + p += IKEV2_MPPE_KEY_LEN; + eap_add_reply(handler->request, "MS-MPPE-Send-Key", p, IKEV2_MPPE_KEY_LEN); + return 0; +} + +/** Compose Radius like message from table of output bytes + * + */ +static int compose_rad_message(uint8_t *out,u_int32_t olen, EAP_DS *eap_ds) { + int len; + + eap_ds->request->type.num = PW_EAP_IKEV2; + eap_ds->request->code = ((struct EAPHeader *)out)->Code; + + if (eap_ds->request->code > PW_EAP_REQUEST || (olen <= 4)) { + eap_ds->request->type.data = NULL; + eap_ds->request->type.length = 0; + + return 0; + } + + len = ntohs(((struct EAPHeader *)out)->Length); + + eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, len); + if (!eap_ds->request->type.data) return 1; + + memcpy(eap_ds->request->type.data, out + 5, len - 5); + eap_ds->request->type.length = len - 5; + + return 0; +} + +/** Free memory after EAP-IKEv2 module usage + * + */ +static int mod_detach(void *instance) +{ + struct ikev2_ctx *data = (struct ikev2_ctx *) instance; + + if (data) { + Free_ikev2_ctx(data); + data = NULL; + } + return 0; +} + +/** Free memory after finished IKEv2 session + * + */ +static void ikev2_free_opaque(void *opaque) +{ + + int fast_deleted; + struct IKEv2Data *ikev2_data=(struct IKEv2Data*)opaque; + + DEBUG(IKEv2_LOG_PREFIX "Free session data"); + + if (ikev2_data->session) { + if (ikev2_data->session->Status != IKEv2_SST_ESTABLISHED) { + DEBUG(IKEv2_LOG_PREFIX "Unfinished IKEv2 session - cleanup!!!"); + IKEv2EndSession(ikev2_data->i2, ikev2_data->session); + ikev2_data->session = NULL; + } else { + DEBUG(IKEv2_LOG_PREFIX "Unfinished IKEv2 session - keep it!!!"); + ikev2_data->session = NULL; + } + } + + fast_deleted = FreeSessionIfExpired(ikev2_data->i2, time(NULL)); + if (fast_deleted) { + DEBUG(IKEv2_LOG_PREFIX "Deleted %d expired IKEv2 sessions", fast_deleted); + } + + free(ikev2_data); +} + +/** Configure EAP-ikev2 handler + * + */ +static int mod_instantiate(CONF_SECTION *conf, void **instance) +{ + int ret; + + struct ikev2_ctx *i2; + rlm_eap_ikev2_t *inst; + + char *server_auth_type, *default_auth_type, *users_file_name; + + ikev2_set_log_callback(vxlogf); + + inst = talloc_zero(conf, rlm_eap_ikev2_t); + if (cf_section_parse(conf, &inst, module_config) < 0) return -1; + + i2 = Create_ikev2_ctx(); + if (!i2) return -1; + *instance = i2; + + /* + * Map our config structure onto the IKEv2 context + */ + memcpy(&i2->trusted, &inst->tls_ca_file, sizeof(i2->trusted)); + memcpy(&i2->pkfile, &inst->tls_private_key_file, sizeof(i2->pkfile)); + memcpy(&i2->pkfile_pwd, &inst->tls_private_key_password, sizeof(i2->pkfile_pwd)); + memcpy(&i2->certfile, &inst->tls_certificate_file, sizeof(i2->certfile)); + memcpy(&i2->id, &inst->id, sizeof(i2->id)); + i2->max_fragment_size = inst->max_fragment_size; + i2->DHCounterMax = inst->dh_counter_max; + i2->sendCertReq = (uint8_t) inst->send_cert_request; + i2->fastExpire = inst->fast_expire; + i2->enableFastDHEx = inst->enable_fast_dhex; + i2->enableFastReconnect = inst->enable_fast_reconnect; + + memcpy(&server_auth_type, &inst->server_auth_type, sizeof(server_auth_type)); + memcpy(&default_auth_type, &inst->default_auth_type, sizeof(default_auth_type)); + memcpy(&users_file_name, &inst->users_file_name, sizeof(users_file_name)); + hexalize(&i2->id, &i2->idlen); + + i2->authtype = rad_get_authtype(server_auth_type); + if (!i2->id) { + ERROR(IKEv2_LOG_PREFIX "'id' configuration option is required!!!"); + return -1; + } + + switch (i2->authtype) { + default: + case IKEv2_AUTH_SK: + break; + + case IKEv2_AUTH_CERT: + if (!i2->certfile || !i2->pkfile) { + ERROR(IKEv2_LOG_PREFIX "'certificate_file' and 'private_key_file' items are required " + "for 'cert' auth type"); + return -1; + } + + if (!file_exists(i2->certfile)) { + ERROR(IKEv2_LOG_PREFIX "Can not open 'certificate_file' %s", i2->certfile); + return -1; + } + + if (!file_exists(i2->pkfile)) { + ERROR(IKEv2_LOG_PREFIX "Can not open 'private_key_file' %s",i2->pkfile); + return -1; + } + break; + } + + if (!i2->trusted) { + AUTH(IKEv2_LOG_PREFIX "'ca_file' item not set, client cert based authentication will fail"); + } else { + if (!file_exists(i2->trusted)) { + ERROR(IKEv2_LOG_PREFIX "Can not open 'ca_file' %s", i2->trusted); + return -1; + } + } + + if (i2->crl_file) { + if (!file_exists(i2->crl_file)) { + ERROR(IKEv2_LOG_PREFIX "Can not open 'crl_file' %s", i2->crl_file); + return -1; + } + } + + i2->idtype = IdTypeFromName(inst->server_id_type); + if (i2->idtype <= 0) { + ERROR(IKEv2_LOG_PREFIX "Unsupported 'idtype': %s", inst->server_id_type); + return -1; + } + + if (rad_load_proposals(i2, conf)) { + ERROR(IKEv2_LOG_PREFIX "Failed to load proposals"); + return -1; + } + + ret = rad_load_credentials(instance, i2, users_file_name, default_auth_type); + if (ret == -1) { + ERROR(IKEv2_LOG_PREFIX "Error while loading users credentials"); + return -1; + } + + i2->x509_store = NULL; + if(CertInit(i2)){ + ERROR(IKEv2_LOG_PREFIX "Error while loading certs/crl"); + return -1; + } + + return 0; +} + +/** Initiate the EAP-ikev2 session by sending a challenge to the peer. + * + */ +static int mod_session_init(void *instance, eap_handler_t *handler) +{ + INFO(IKEv2_LOG_PREFIX "Initiate connection!"); + + struct IKEv2Data *ikev2_data; + struct ikev2_ctx *i2=(struct ikev2_ctx*)instance; + + uint8_t *sikemsg = NULL; + u_int32_t slen = 0; + + uint8_t *out = NULL; + u_int32_t olen = 0; + + struct IKEv2Session *session; + handler->free_opaque = ikev2_free_opaque; + + /* try get respondent FASTID */ + uint8_t const *eap_username; + + eap_username = handler->request->username->vp_octets; + session = FindSessionByFastid(i2, (char const *)eap_username); + if (!session) { + if (IKEv2BeginSession( i2, &session, IKEv2_STY_INITIATOR ) != IKEv2_RET_OK) { + ERROR(IKEv2_LOG_PREFIX "Can't initialize IKEv2 session"); + return 1; + } + } else { + DEBUG(IKEv2_LOG_PREFIX "Fast reconnect procedure start"); + } + session->timestamp=time(NULL); + + ikev2_data = IKEv2Data_new(i2,session); + handler->opaque = ikev2_data; + + if (IKEv2ProcessMsg(i2, NULL , &sikemsg, &slen, session) != IKEv2_RET_OK) { + ERROR(IKEv2_LOG_PREFIX "Error while processing IKEv2 message"); + return 1; + } + + if (slen != 0) { + session->eapMsgID++; + olen = CreateIKEv2Message(i2, sikemsg, slen, false, 0, session, &out ); + if (session->fragdata) { + session->sendfrag = true; + } + } + + if ((olen > 0) && (out!=NULL)) { + if (compose_rad_message(out, olen, handler->eap_ds)) { + free(out); + return 0; + } + free(out); + } + + /* + * We don't need to authorize the user at this point. + * + * We also don't need to keep the challenge, as it's + * stored in 'handler->eap_ds', which will be given back + * to us... + */ + handler->stage = PROCESS; + return 1; +} + +/** Authenticate a previously sent challenge + * + */ +static int mod_process(void *instance, eap_handler_t *handler) +{ + uint8_t *in; + uint8_t *out = NULL; + + uint8_t *ikemsg; + u_int32_t len; + + uint8_t *sikemsg = NULL; //out message + u_int32_t slen = 0; + + u_int32_t olen = 0; + struct ikev2_ctx *i2 = (struct ikev2_ctx*)instance; + struct EAPHeader *hdr; + + struct IKEv2Data *ikev2_data; + struct IKEv2Session *session; + + INFO(IKEv2_LOG_PREFIX "authenticate" ); + + rad_assert(handler->request != NULL); + rad_assert(handler->stage == PROCESS); + + EAP_DS *eap_ds=handler->eap_ds; + if (!eap_ds || + !eap_ds->response || + (eap_ds->response->code != PW_IKEV2_RESPONSE) || + eap_ds->response->type.num != PW_EAP_IKEV2 || + !eap_ds->response->type.data) { + ERROR(IKEv2_LOG_PREFIX "corrupted data"); + return -1; + } + + in = talloc_array(eap_ds, uint8_t, eap_ds->response->length); + if (in){ + ERROR(IKEv2_LOG_PREFIX "alloc error"); + return -1; + } + + rad_assert(in != NULL); + hdr = (struct EAPHeader *)in; + + hdr->Code = eap_ds->response->code; + hdr->Id = eap_ds->response->id; + hdr->Length = htons(eap_ds->response->length); + hdr->Type = eap_ds->response->type.num; + memcpy(in + 5, eap_ds->response->type.data, eap_ds->response->length - 5); + + ikev2_data = (struct IKEv2Data*)handler->opaque; + session = ikev2_data->session; + session->timestamp = time(NULL); + + if (!session->fragdata) session->sendfrag = false; + + if (session->sendfrag && !ParseFragmentAck(in, session)){ + session->eapMsgID = eap_ds->response->id + 1; + + olen = CreateIKEv2Message(i2, NULL, 0, false, hdr->Id, session, (uint8_t **)&out); + talloc_free(in); + + if (compose_rad_message(out,olen,handler->eap_ds)) { + free(out); + return 0; + } + + free(out); + return 1; + } + + session->eapMsgID = eap_ds->response->id + 1; + + if (ParseIKEv2Message(in, &ikemsg, &len, session)){ + if (ikemsg != NULL) free(ikemsg); + + handler->eap_ds->request->code=PW_EAP_FAILURE; + INFO(IKEv2_LOG_PREFIX "Discarded packet"); + + return 1; + } + + /* Send fragment ack */ + if (!ikemsg || !len) { + if (session->SK_ready) session->include_integ = 1; + + olen = CreateFragmentAck(in, &out, session); // confirm fragment + TALLOC_FREE(in); + + if (compose_rad_message(out,olen,handler->eap_ds)) { + free(out); + return 0; + } + + free(out); + return 1; + } + TALLOC_FREE(in); + + if (IKEv2ProcessMsg(i2, ikemsg, &sikemsg, &slen, session) != IKEv2_RET_OK) { + INFO(IKEv2_LOG_PREFIX "EAP_STATE_DISCARD"); + //session->State = EAP_STATE_DISCARD; + free(out); + return 1; + } + + free(ikemsg); + + /* If there is there is something to send */ + if (slen != 0){ + olen = CreateIKEv2Message(i2, sikemsg, slen, false, 0, session, &out); + if (session->fragdata) session->sendfrag = true; + } else { + if (session->Status == IKEv2_SST_FAILED ) { + INFO(IKEv2_LOG_PREFIX "FAILED"); + olen = CreateResultMessage( false, session, &out ); + } + + if(session->Status == IKEv2_SST_ESTABLISHED) { + INFO(IKEv2_LOG_PREFIX "SUCCESS"); + olen = CreateResultMessage(true, session, &out); + session->fFastReconnect = i2->enableFastReconnect; + + GenEapKeys(session ,EAP_IKEv2_KEY_LEN); + set_mppe_keys(handler); + } + + // keep sessions in memory, only reference cleared + ikev2_data->session = NULL; + } + if ((olen > 0) && (out != NULL)){ + if (compose_rad_message(out, olen, handler->eap_ds)){ + free(out); + return 0; + } + } + + free(out); + 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_ikev2; +rlm_eap_module_t rlm_eap_ikev2 = { + .name = "eap_ikev2", + .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 */ + .detach = mod_detach /* detach */ +}; diff --git a/src/modules/rlm_eap/types/rlm_eap_md5/all.mk b/src/modules/rlm_eap/types/rlm_eap_md5/all.mk new file mode 100644 index 0000000..528ee82 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_md5/all.mk @@ -0,0 +1,12 @@ +TARGETNAME := rlm_eap_md5 + +ifneq "$(TARGETNAME)" "" +TARGET := $(TARGETNAME).a +endif + +SOURCES := $(TARGETNAME).c eap_md5.c + +SRC_CFLAGS := +TGT_LDLIBS := +SRC_INCDIRS := ../../ ../../libeap/ +TGT_PREREQS := libfreeradius-eap.a diff --git a/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.c b/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.c new file mode 100644 index 0000000..e8acb5c --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.c @@ -0,0 +1,229 @@ +/* + * eap_md5.c EAP MD5 functionality. + * + * 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 2000,2001,2006 The FreeRADIUS server project + * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com> + */ + +/* + * + * MD5 Packet Format in EAP Type-Data + * --- ------ ------ -- --- --------- + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Value-Size | Value ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Name ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +RCSID("$Id$") + +#include <stdio.h> +#include <stdlib.h> +#include "eap.h" + +#include "eap_md5.h" +#include <freeradius-devel/md5.h> + +/* + * We expect only RESPONSE for which SUCCESS or FAILURE is sent back + */ +MD5_PACKET *eapmd5_extract(EAP_DS *eap_ds) +{ + md5_packet_t *data; + MD5_PACKET *packet; + unsigned short name_len; + + /* + * We need a response, of type EAP-MD5, with at least + * one byte of type data (EAP-MD5) following the 4-byte + * EAP-Packet header. + */ + if (!eap_ds || + !eap_ds->response || + (eap_ds->response->code != PW_MD5_RESPONSE) || + eap_ds->response->type.num != PW_EAP_MD5 || + !eap_ds->response->type.data || + (eap_ds->response->length <= MD5_HEADER_LEN) || + (eap_ds->response->type.data[0] <= 0)) { + ERROR("rlm_eap_md5: corrupted data"); + return NULL; + } + + packet = talloc_zero(eap_ds, MD5_PACKET); + if (!packet) return NULL; + + /* + * Code & id for MD5 & EAP are same + * + * but md5_length = length of the EAP-MD5 data, which + * doesn't include the EAP header, or the octet saying + * EAP-MD5. + */ + packet->code = eap_ds->response->code; + packet->id = eap_ds->response->id; + packet->length = eap_ds->response->length - (MD5_HEADER_LEN + 1); + + /* + * Sanity check the EAP-MD5 packet sent to us + * by the client. + */ + data = (md5_packet_t *)eap_ds->response->type.data; + + /* + * Already checked the size above. + */ + packet->value_size = data->value_size; + + /* + * Allocate room for the data, and copy over the data. + */ + packet->value = talloc_array(packet, uint8_t, packet->value_size); + if (!packet->value) { + talloc_free(packet); + return NULL; + } + memcpy(packet->value, data->value_name, packet->value_size); + + /* + * Name is optional and is present after Value, but we + * need to check for it, as eapmd5_compose() + */ + name_len = packet->length - (packet->value_size + 1); + if (name_len) { + packet->name = talloc_array(packet, char, name_len + 1); + if (!packet->name) { + talloc_free(packet); + return NULL; + } + memcpy(packet->name, data->value_name + packet->value_size, + name_len); + packet->name[name_len] = 0; + } + + return packet; +} + + +/* + * verify = MD5(id+password+challenge_sent) + */ +int eapmd5_verify(MD5_PACKET *packet, VALUE_PAIR* password, + uint8_t *challenge) +{ + char *ptr; + char string[1 + MAX_STRING_LEN*2]; + uint8_t digest[16]; + unsigned short len; + + /* + * Sanity check it. + */ + if (packet->value_size != 16) { + ERROR("rlm_eap_md5: Expected 16 bytes of response to challenge, got %d", packet->value_size); + return 0; + } + + len = 0; + ptr = string; + + /* + * This is really rad_chap_pwencode()... + */ + *ptr++ = packet->id; + len++; + memcpy(ptr, password->vp_strvalue, password->vp_length); + ptr += password->vp_length; + len += password->vp_length; + + /* + * The challenge size is hard-coded. + */ + memcpy(ptr, challenge, MD5_CHALLENGE_LEN); + len += MD5_CHALLENGE_LEN; + + fr_md5_calc(digest, (u_char *)string, len); + + /* + * The length of the response is always 16 for MD5. + */ + if (rad_digest_cmp(digest, packet->value, 16) != 0) { + DEBUG("EAP-MD5 digests do not match."); + return 0; + } + + return 1; +} + +/* + * Compose the portions of the reply packet specific to the + * EAP-MD5 protocol, in the EAP reply typedata + */ +int eapmd5_compose(EAP_DS *eap_ds, MD5_PACKET *reply) +{ + uint8_t *ptr; + unsigned short name_len; + + /* + * We really only send Challenge (EAP-Identity), + * and EAP-Success, and EAP-Failure. + */ + if (reply->code < 3) { + eap_ds->request->type.num = PW_EAP_MD5; + + rad_assert(reply->length > 0); + + eap_ds->request->type.data = talloc_array(eap_ds->request, + uint8_t, + reply->length); + if (!eap_ds->request->type.data) { + talloc_free(reply); + return 0; + } + ptr = eap_ds->request->type.data; + *ptr++ = (uint8_t)(reply->value_size & 0xFF); + memcpy(ptr, reply->value, reply->value_size); + + /* Just the Challenge length */ + eap_ds->request->type.length = reply->value_size + 1; + + /* + * Return the name, if necessary. + * + * Don't see why this is *ever* necessary... + */ + name_len = reply->length - (reply->value_size + 1); + if (name_len && reply->name) { + ptr += reply->value_size; + memcpy(ptr, reply->name, name_len); + /* Challenge length + Name length */ + eap_ds->request->type.length += name_len; + } + } else { + eap_ds->request->type.length = 0; + /* TODO: In future we might add message here wrt rfc1994 */ + } + eap_ds->request->code = reply->code; + talloc_free(reply); + + return 1; +} diff --git a/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.h b/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.h new file mode 100644 index 0000000..aafa407 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.h @@ -0,0 +1,52 @@ +#ifndef _EAP_MD5_H +#define _EAP_MD5_H + +RCSIDH(eap_md5_h, "$Id$") + +#include "eap.h" + +#define PW_MD5_CHALLENGE 1 +#define PW_MD5_RESPONSE 2 +#define PW_MD5_SUCCESS 3 +#define PW_MD5_FAILURE 4 +#define PW_MD5_MAX_CODES 4 + +#define MD5_HEADER_LEN 4 +#define MD5_CHALLENGE_LEN 16 + +/* + **** + * EAP - MD5 does not specify code, id & length but chap specifies them, + * for generalization purpose, complete header should be sent + * and not just value_size, value and name. + * future implementation. + * + * Huh? What does that mean? + */ + +/* eap packet structure */ +typedef struct md5_packet_t { +/* + uint8_t code; + uint8_t id; + uint16_t length; +*/ + uint8_t value_size; + uint8_t value_name[1]; +} md5_packet_t; + +typedef struct md5_packet { + unsigned char code; + unsigned char id; + unsigned short length; + unsigned char value_size; + unsigned char *value; + char *name; +} MD5_PACKET; + +/* function declarations here */ + +int eapmd5_compose(EAP_DS *auth, MD5_PACKET *reply); +MD5_PACKET *eapmd5_extract(EAP_DS *auth); +int eapmd5_verify(MD5_PACKET *pkt, VALUE_PAIR* pwd, uint8_t *ch); +#endif /*_EAP_MD5_H*/ diff --git a/src/modules/rlm_eap/types/rlm_eap_md5/rlm_eap_md5.c b/src/modules/rlm_eap/types/rlm_eap_md5/rlm_eap_md5.c new file mode 100644 index 0000000..2fa0077 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_md5/rlm_eap_md5.c @@ -0,0 +1,168 @@ +/* + * rlm_eap_md5.c Handles 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 2000,2001,2006 The FreeRADIUS server project + * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com> + */ + +RCSID("$Id$") + +#include <stdio.h> +#include <stdlib.h> + +#include "eap_md5.h" + +#include <freeradius-devel/rad_assert.h> +#include <freeradius-devel/md5.h> + +/* + * Initiate the EAP-MD5 session by sending a challenge to the peer. + */ +static int mod_session_init(UNUSED void *instance, eap_handler_t *handler) +{ + int i; + MD5_PACKET *reply; + REQUEST *request = handler->request; + + /* + * Allocate an EAP-MD5 packet. + */ + reply = talloc(handler, MD5_PACKET); + if (!reply) { + return 0; + } + + /* + * Fill it with data. + */ + reply->code = PW_MD5_CHALLENGE; + reply->length = 1 + MD5_CHALLENGE_LEN; /* one byte of value size */ + reply->value_size = MD5_CHALLENGE_LEN; + + /* + * Allocate user data. + */ + reply->value = talloc_array(reply, uint8_t, reply->value_size); + if (!reply->value) { + talloc_free(reply); + return 0; + } + + /* + * Get a random challenge. + */ + for (i = 0; i < reply->value_size; i++) { + reply->value[i] = fr_rand(); + } + RDEBUG2("Issuing MD5 Challenge"); + + /* + * Keep track of the challenge. + */ + handler->opaque = talloc_array(handler, uint8_t, reply->value_size); + rad_assert(handler->opaque != NULL); + memcpy(handler->opaque, reply->value, reply->value_size); + handler->free_opaque = NULL; + + /* + * Compose the EAP-MD5 packet out of the data structure, + * and free it. + */ + eapmd5_compose(handler->eap_ds, reply); + + /* + * We don't need to authorize the user at this point. + * + * We also don't need to keep the challenge, as it's + * stored in 'handler->eap_ds', which will be given back + * to us... + */ + handler->stage = PROCESS; + + return 1; +} + +/* + * Authenticate a previously sent challenge. + */ +static int mod_process(UNUSED void *arg, eap_handler_t *handler) +{ + MD5_PACKET *packet; + MD5_PACKET *reply; + VALUE_PAIR *password; + REQUEST *request = handler->request; + + /* + * Get the Cleartext-Password for this user. + */ + rad_assert(handler->request != NULL); + rad_assert(handler->stage == PROCESS); + + password = fr_pair_find_by_num(handler->request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY); + if (!password) { + REDEBUG2("Cleartext-Password is required for EAP-MD5 authentication"); + return 0; + } + + /* + * Extract the EAP-MD5 packet. + */ + if (!(packet = eapmd5_extract(handler->eap_ds))) + return 0; + + /* + * Create a reply, and initialize it. + */ + reply = talloc(packet, MD5_PACKET); + if (!reply) { + talloc_free(packet); + return 0; + } + reply->id = handler->eap_ds->request->id; + reply->length = 0; + + /* + * Verify the received packet against the previous packet + * (i.e. challenge) which we sent out. + */ + if (eapmd5_verify(packet, password, handler->opaque)) { + reply->code = PW_MD5_SUCCESS; + } else { + reply->code = PW_MD5_FAILURE; + } + + /* + * Compose the EAP-MD5 packet out of the data structure, + * and free it. + */ + eapmd5_compose(handler->eap_ds, reply); + talloc_free(packet); + 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_md5; +rlm_eap_module_t rlm_eap_md5 = { + .name = "eap_md5", + .session_init = mod_session_init, /* Initialise a new EAP session */ + .process = mod_process /* Process next round of EAP method */ +}; diff --git a/src/modules/rlm_eap/types/rlm_eap_mschapv2/all.mk b/src/modules/rlm_eap/types/rlm_eap_mschapv2/all.mk new file mode 100644 index 0000000..d57c636 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_mschapv2/all.mk @@ -0,0 +1,12 @@ +TARGETNAME := rlm_eap_mschapv2 + +ifneq "$(TARGETNAME)" "" +TARGET := $(TARGETNAME).a +endif + +SOURCES := $(TARGETNAME).c + +SRC_CFLAGS := +TGT_LDLIBS := +SRC_INCDIRS := ../../ ../../libeap/ +TGT_PREREQS := libfreeradius-eap.a diff --git a/src/modules/rlm_eap/types/rlm_eap_mschapv2/eap_mschapv2.h b/src/modules/rlm_eap/types/rlm_eap_mschapv2/eap_mschapv2.h new file mode 100644 index 0000000..1ce2470 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_mschapv2/eap_mschapv2.h @@ -0,0 +1,51 @@ +#ifndef _EAP_MSCHAPV2_H +#define _EAP_MSCHAPV2_H + +RCSIDH(eap_mschapv2_h, "$Id$") + +#include "eap.h" + +/* + * draft-kamath-pppext-eap-mschapv2-00.txt says: + * + * Supplicant FreeRADIUS + * <-- challenge + * response --> + * <-- success + * success --> + * + * But what we often see is: + * + * Supplicant FreeRADIUS + * <-- challenge + * response --> + * <-- success + * ack --> + */ +#define PW_EAP_MSCHAPV2_ACK 0 +#define PW_EAP_MSCHAPV2_CHALLENGE 1 +#define PW_EAP_MSCHAPV2_RESPONSE 2 +#define PW_EAP_MSCHAPV2_SUCCESS 3 +#define PW_EAP_MSCHAPV2_FAILURE 4 +#define PW_EAP_MSCHAPV2_CHGPASSWD 7 +#define PW_EAP_MSCHAPV2_MAX_CODES 7 + +#define MSCHAPV2_HEADER_LEN 5 +#define MSCHAPV2_CHALLENGE_LEN 16 +#define MSCHAPV2_RESPONSE_LEN 50 + +typedef struct mschapv2_header_t { + uint8_t opcode; + uint8_t mschapv2_id; + uint8_t ms_length[2]; + uint8_t value_size; +} mschapv2_header_t; + +typedef struct mschapv2_opaque_t { + int code; + uint8_t challenge[MSCHAPV2_CHALLENGE_LEN]; + VALUE_PAIR *mppe_keys; + VALUE_PAIR *reply; +} mschapv2_opaque_t; + +#endif /*_EAP_MSCHAPV2_H*/ diff --git a/src/modules/rlm_eap/types/rlm_eap_mschapv2/rlm_eap_mschapv2.c b/src/modules/rlm_eap/types/rlm_eap_mschapv2/rlm_eap_mschapv2.c new file mode 100644 index 0000000..c1a0045 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_mschapv2/rlm_eap_mschapv2.c @@ -0,0 +1,757 @@ +/* + * rlm_eap_mschapv2.c Handles 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 2003,2006 The FreeRADIUS server project + */ + +RCSID("$Id$") + +#include <stdio.h> +#include <stdlib.h> + +#include "eap_mschapv2.h" + +#include <freeradius-devel/rad_assert.h> + +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[] = { + { "with_ntdomain_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_mschapv2_t, with_ntdomain_hack), "no" }, + + { "send_error", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_mschapv2_t, send_error), "no" }, + { "identity", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_mschapv2_t, identity), NULL }, + CONF_PARSER_TERMINATOR +}; + + +static void fix_mppe_keys(eap_handler_t *handler, mschapv2_opaque_t *data) +{ + fr_pair_list_mcopy_by_num(data, &data->mppe_keys, &handler->request->reply->vps, 7, VENDORPEC_MICROSOFT, TAG_ANY); + fr_pair_list_mcopy_by_num(data, &data->mppe_keys, &handler->request->reply->vps, 8, VENDORPEC_MICROSOFT, TAG_ANY); + fr_pair_list_mcopy_by_num(data, &data->mppe_keys, &handler->request->reply->vps, 16, VENDORPEC_MICROSOFT, TAG_ANY); + fr_pair_list_mcopy_by_num(data, &data->mppe_keys, &handler->request->reply->vps, 17, VENDORPEC_MICROSOFT, TAG_ANY); +} + +/* + * Attach the module. + */ +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; + + /* + * Parse the configuration attributes. + */ + if (cf_section_parse(cs, inst, module_config) < 0) { + return -1; + } + + if (inst->identity && (strlen(inst->identity) > 255)) { + cf_log_err_cs(cs, "identity is too long"); + return -1; + } + + if (!inst->identity) { + 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; +} + + +/* + * Compose the response. + */ +static int eapmschapv2_compose(rlm_eap_mschapv2_t *inst, eap_handler_t *handler, VALUE_PAIR *reply) +{ + uint8_t *ptr; + int16_t length; + mschapv2_header_t *hdr; + EAP_DS *eap_ds = handler->eap_ds; + REQUEST *request = handler->request; + + eap_ds->request->code = PW_EAP_REQUEST; + eap_ds->request->type.num = PW_EAP_MSCHAPV2; + + /* + * Always called with vendor Microsoft + */ + switch (reply->da->attr) { + case PW_MSCHAP_CHALLENGE: + /* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Code | Identifier | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | OpCode | MS-CHAPv2-ID | MS-Length... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | MS-Length | Value-Size | Challenge... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Challenge... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Server Name... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + length = MSCHAPV2_HEADER_LEN + MSCHAPV2_CHALLENGE_LEN + strlen(inst->identity); + eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, length); + + /* + * Allocate room for the EAP-MS-CHAPv2 data. + */ + if (!eap_ds->request->type.data) { + return 0; + } + eap_ds->request->type.length = length; + + ptr = eap_ds->request->type.data; + hdr = (mschapv2_header_t *) ptr; + + hdr->opcode = PW_EAP_MSCHAPV2_CHALLENGE; + hdr->mschapv2_id = eap_ds->response->id + 1; + length = htons(length); + memcpy(hdr->ms_length, &length, sizeof(uint16_t)); + hdr->value_size = MSCHAPV2_CHALLENGE_LEN; + + ptr += MSCHAPV2_HEADER_LEN; + + /* + * Copy the Challenge, success, or error over. + */ + memcpy(ptr, reply->vp_octets, reply->vp_length); + + memcpy((ptr + reply->vp_length), inst->identity, strlen(inst->identity)); + break; + + case PW_MSCHAP2_SUCCESS: + /* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Code | Identifier | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | OpCode | MS-CHAPv2-ID | MS-Length... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | MS-Length | Message... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + RDEBUG2("MSCHAP Success"); + length = 46; + eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, length); + /* + * Allocate room for the EAP-MS-CHAPv2 data. + */ + if (!eap_ds->request->type.data) { + return 0; + } + memset(eap_ds->request->type.data, 0, length); + eap_ds->request->type.length = length; + + eap_ds->request->type.data[0] = PW_EAP_MSCHAPV2_SUCCESS; + eap_ds->request->type.data[1] = eap_ds->response->id; + length = htons(length); + memcpy((eap_ds->request->type.data + 2), &length, sizeof(uint16_t)); + memcpy((eap_ds->request->type.data + 4), reply->vp_strvalue + 1, 42); + break; + + case PW_MSCHAP_ERROR: + REDEBUG("MSCHAP Failure"); + length = 4 + reply->vp_length - 1; + eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, length); + + /* + * Allocate room for the EAP-MS-CHAPv2 data. + */ + if (!eap_ds->request->type.data) return 0; + memset(eap_ds->request->type.data, 0, length); + eap_ds->request->type.length = length; + + eap_ds->request->type.data[0] = PW_EAP_MSCHAPV2_FAILURE; + eap_ds->request->type.data[1] = eap_ds->response->id; + length = htons(length); + memcpy((eap_ds->request->type.data + 2), &length, sizeof(uint16_t)); + /* + * Copy the entire failure message. + */ + memcpy((eap_ds->request->type.data + 4), + reply->vp_strvalue + 1, reply->vp_length - 1); + break; + + default: + RERROR("Internal sanity check failed"); + return 0; + } + + return 1; +} + + +/* + * Initiate the EAP-MSCHAPV2 session by sending a challenge to the peer. + */ +static int mod_session_init(void *instance, eap_handler_t *handler) +{ + int i; + VALUE_PAIR *challenge; + mschapv2_opaque_t *data; + REQUEST *request = handler->request; + uint8_t *p; + bool created_challenge = false; + rlm_eap_mschapv2_t *inst = instance; + + challenge = fr_pair_find_by_num(request->config, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT, TAG_ANY); + if (challenge && (challenge->vp_length != MSCHAPV2_CHALLENGE_LEN)) { + RWDEBUG("control:MS-CHAP-Challenge is incorrect length. Ignoring it."); + challenge = NULL; + } + + if (!challenge) { + created_challenge = true; + challenge = fr_pair_make(handler, NULL, "MS-CHAP-Challenge", NULL, T_OP_EQ); + + /* + * Get a random challenge. + */ + challenge->vp_length = MSCHAPV2_CHALLENGE_LEN; + challenge->vp_octets = p = talloc_array(challenge, uint8_t, challenge->vp_length); + for (i = 0; i < MSCHAPV2_CHALLENGE_LEN; i++) { + p[i] = fr_rand(); + } + } + RDEBUG2("Issuing Challenge"); + + /* + * Keep track of the challenge. + */ + data = talloc_zero(handler, mschapv2_opaque_t); + rad_assert(data != NULL); + + /* + * We're at the stage where we're challenging the user. + */ + data->code = PW_EAP_MSCHAPV2_CHALLENGE; + memcpy(data->challenge, challenge->vp_octets, MSCHAPV2_CHALLENGE_LEN); + data->mppe_keys = NULL; + data->reply = NULL; + + handler->opaque = data; + + /* + * Compose the EAP-MSCHAPV2 packet out of the data structure, + * and free it. + */ + eapmschapv2_compose(inst, handler, challenge); + if (created_challenge) fr_pair_list_free(&challenge); + +#ifdef WITH_PROXY + /* + * The EAP session doesn't have enough information to + * proxy the "inside EAP" protocol. Disable EAP proxying. + */ + handler->request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP; +#endif + + /* + * We don't need to authorize the user at this point. + * + * We also don't need to keep the challenge, as it's + * stored in 'handler->eap_ds', which will be given back + * to us... + */ + handler->stage = PROCESS; + + return 1; +} + +#ifdef WITH_PROXY +/* + * Do post-proxy processing, + * 0 = fail + * 1 = OK. + * + * Called from rlm_eap.c, eap_postproxy(). + */ +static int CC_HINT(nonnull) mschap_postproxy(eap_handler_t *handler, UNUSED void *tunnel_data) +{ + VALUE_PAIR *response = NULL; + mschapv2_opaque_t *data; + REQUEST *request = handler->request; + + data = (mschapv2_opaque_t *) handler->opaque; + rad_assert(request != NULL); + + RDEBUG2("Passing reply from proxy back into the tunnel %d", request->reply->code); + + /* + * There is only a limited number of possibilities. + */ + switch (request->reply->code) { + case PW_CODE_ACCESS_ACCEPT: + RDEBUG2("Proxied authentication succeeded"); + + /* + * Move the attribute, so it doesn't go into + * the reply. + */ + fr_pair_list_mcopy_by_num(data, &response, &request->reply->vps, PW_MSCHAP2_SUCCESS, VENDORPEC_MICROSOFT, TAG_ANY); + break; + + default: + case PW_CODE_ACCESS_REJECT: + REDEBUG("Proxied authentication was rejected"); + return 0; + } + + /* + * No response, die. + */ + if (!response) { + REDEBUG("Proxied reply contained no MS-CHAP2-Success or MS-CHAP-Error"); + return 0; + } + + /* + * Done doing EAP proxy stuff. + */ + request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP; + eapmschapv2_compose(NULL, handler, response); + data->code = PW_EAP_MSCHAPV2_SUCCESS; + + /* + * Delete MPPE keys & encryption policy + * + * FIXME: Use intelligent names... + */ + fix_mppe_keys(handler, data); + + /* + * Save any other attributes for re-use in the final + * access-accept e.g. vlan, etc. This lets the PEAP + * use_tunneled_reply code work + */ + data->reply = fr_pair_list_copy(data, request->reply->vps); + + /* + * And we need to challenge the user, not ack/reject them, + * so we re-write the ACK to a challenge. Yuck. + */ + request->reply->code = PW_CODE_ACCESS_CHALLENGE; + fr_pair_list_free(&response); + + return 1; +} +#endif + +/* + * Authenticate a previously sent challenge. + */ +static int CC_HINT(nonnull) mod_process(void *arg, eap_handler_t *handler) +{ + int rcode, ccode; + uint8_t *p; + size_t length; + char *q; + mschapv2_opaque_t *data; + EAP_DS *eap_ds = handler->eap_ds; + VALUE_PAIR *challenge, *response, *name; + rlm_eap_mschapv2_t *inst = (rlm_eap_mschapv2_t *) arg; + REQUEST *request = handler->request; + + rad_assert(handler->stage == PROCESS); + + data = (mschapv2_opaque_t *) handler->opaque; + + /* + * Sanity check the response. + */ + if (eap_ds->response->length <= 5) { + REDEBUG("corrupted data"); + return 0; + } + + ccode = eap_ds->response->type.data[0]; + + switch (data->code) { + case PW_EAP_MSCHAPV2_FAILURE: + if (ccode == PW_EAP_MSCHAPV2_RESPONSE) { + RDEBUG2("Authentication re-try from client after we sent a failure"); + break; + } + + /* + * if we sent error 648 (password expired) to the client + * we might get an MSCHAP-CPW packet here; turn it into a + * regular MS-CHAP2-CPW packet and pass it to rlm_mschap + * (or proxy it, I guess) + */ + if (ccode == PW_EAP_MSCHAPV2_CHGPASSWD) { + VALUE_PAIR *cpw; + int mschap_id = eap_ds->response->type.data[1]; + int copied = 0 ,seq = 1; + + RDEBUG2("Password change packet received"); + + challenge = pair_make_request("MS-CHAP-Challenge", NULL, T_OP_EQ); + if (!challenge) return 0; + fr_pair_value_memcpy(challenge, data->challenge, MSCHAPV2_CHALLENGE_LEN); + + cpw = pair_make_request("MS-CHAP2-CPW", NULL, T_OP_EQ); + cpw->vp_length = 68; + + cpw->vp_octets = p = talloc_array(cpw, uint8_t, cpw->vp_length); + p[0] = 7; + p[1] = mschap_id; + memcpy(p + 2, eap_ds->response->type.data + 520, 66); + + /* + * break the encoded password into VPs (3 of them) + */ + while (copied < 516) { + VALUE_PAIR *nt_enc; + + int to_copy = 516 - copied; + if (to_copy > 243) to_copy = 243; + + nt_enc = pair_make_request("MS-CHAP-NT-Enc-PW", NULL, T_OP_ADD); + nt_enc->vp_length = 4 + to_copy; + + nt_enc->vp_octets = p = talloc_array(nt_enc, uint8_t, nt_enc->vp_length); + + p[0] = 6; + p[1] = mschap_id; + p[2] = 0; + p[3] = seq++; + + memcpy(p + 4, eap_ds->response->type.data + 4 + copied, to_copy); + copied += to_copy; + } + + RDEBUG2("Built change password packet"); + rdebug_pair_list(L_DBG_LVL_2, request, request->packet->vps, NULL); + + /* + * jump to "authentication" + */ + goto packet_ready; + } + + /* + * we sent a failure and are expecting a failure back + */ + if (ccode != PW_EAP_MSCHAPV2_FAILURE) { + REDEBUG("Sent FAILURE expecting FAILURE but got %d", ccode); + return 0; + } + +failure: + request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP; + eap_ds->request->code = PW_EAP_FAILURE; + return 1; + + case PW_EAP_MSCHAPV2_SUCCESS: + /* + * we sent a success to the client; some clients send a + * success back as-per the RFC, some send an ACK. Permit + * both, I guess... + */ + + switch (ccode) { + case PW_EAP_MSCHAPV2_SUCCESS: + eap_ds->request->code = PW_EAP_SUCCESS; + + fr_pair_list_mcopy_by_num(request->reply, &request->reply->vps, &data->mppe_keys, 0, 0, TAG_ANY); + /* FALL-THROUGH */ + + case PW_EAP_MSCHAPV2_ACK: +#ifdef WITH_PROXY + /* + * It's a success. Don't proxy it. + */ + request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP; +#endif + fr_pair_list_mcopy_by_num(request->reply, &request->reply->vps, &data->reply, 0, 0, TAG_ANY); + return 1; + } + REDEBUG("Sent SUCCESS expecting SUCCESS (or ACK) but got %d", ccode); + return 0; + + case PW_EAP_MSCHAPV2_CHALLENGE: + if (ccode == PW_EAP_MSCHAPV2_FAILURE) goto failure; + + /* + * we sent a challenge, expecting a response + */ + if (ccode != PW_EAP_MSCHAPV2_RESPONSE) { + REDEBUG("Sent CHALLENGE expecting RESPONSE but got %d", ccode); + return 0; + } + /* authentication happens below */ + break; + + default: + /* should never happen */ + REDEBUG("Unknown state %d", data->code); + return 0; + } + + + /* + * Ensure that we have at least enough data + * to do the following checks. + * + * EAP header (4), EAP type, MS-CHAP opcode, + * MS-CHAP ident, MS-CHAP data length (2), + * MS-CHAP value length. + */ + if (eap_ds->response->length < (4 + 1 + 1 + 1 + 2 + 1)) { + REDEBUG("Response is too short"); + return 0; + } + + /* + * 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) && + (eap_ds->response->type.data[4] != 16)) { + REDEBUG("Response is of incorrect length %d", eap_ds->response->type.data[4]); + return 0; + } + + /* + * The MS-Length field is 5 + value_size + length + * of name, which is put after the response. + */ + length = (eap_ds->response->type.data[2] << 8) | eap_ds->response->type.data[3]; + if ((length < (5 + 49)) || (length > (256 + 5 + 49))) { + REDEBUG("Response contains contradictory length %zu %d", length, 5 + 49); + return 0; + } + + /* + * We now know that the user has sent us a response + * to the challenge. Let's try to authenticate it. + * + * We do this by taking the challenge from 'data', + * the response from the EAP packet, and creating VALUE_PAIR's + * to pass to the 'mschap' module. This is a little wonky, + * but it works. + */ + challenge = pair_make_request("MS-CHAP-Challenge", NULL, T_OP_EQ); + if (!challenge) return 0; + fr_pair_value_memcpy(challenge, data->challenge, MSCHAPV2_CHALLENGE_LEN); + + response = pair_make_request("MS-CHAP2-Response", NULL, T_OP_EQ); + if (!response) return 0; + response->vp_length = MSCHAPV2_RESPONSE_LEN; + response->vp_octets = p = talloc_array(response, uint8_t, response->vp_length); + + p[0] = eap_ds->response->type.data[1]; + p[1] = eap_ds->response->type.data[5 + MSCHAPV2_RESPONSE_LEN]; + memcpy(p + 2, &eap_ds->response->type.data[5], MSCHAPV2_RESPONSE_LEN - 2); + + name = pair_make_request("MS-CHAP-User-Name", NULL, T_OP_EQ); + if (!name) return 0; + + /* + * MS-Length - MS-Value - 5. + */ + name->vp_length = length - 49 - 5; + name->vp_strvalue = q = talloc_array(name, char, name->vp_length + 1); + memcpy(q, &eap_ds->response->type.data[4 + MSCHAPV2_RESPONSE_LEN], name->vp_length); + q[name->vp_length] = '\0'; + +packet_ready: + +#ifdef WITH_PROXY + /* + * If this options is set, then we do NOT authenticate the + * user here. Instead, now that we've added the MS-CHAP + * attributes to the request, we STOP, and let the outer + * tunnel code handle it. + * + * This means that the outer tunnel code will DELETE the + * EAP attributes, and proxy the MS-CHAP attributes to a + * home server. + */ + if (request->options & RAD_REQUEST_OPTION_PROXY_EAP) { + char *username = NULL; + eap_tunnel_data_t *tunnel; + + RDEBUG2("Cancelling authentication and letting it be proxied"); + + /* + * Set up the callbacks for the tunnel + */ + tunnel = talloc_zero(request, eap_tunnel_data_t); + + tunnel->tls_session = arg; + tunnel->callback = mschap_postproxy; + + /* + * Associate the callback with the request. + */ + rcode = request_data_add(request, + request->proxy, + REQUEST_DATA_EAP_TUNNEL_CALLBACK, + tunnel, false); + rad_assert(rcode == 0); + + /* + * The State attribute is NOT supposed to + * go into the proxied packet, it will confuse + * other RADIUS servers, and they will discard + * the request. + * + * The PEAP module will take care of adding + * the State attribute back, before passing + * the handler & request back into the tunnel. + */ + fr_pair_delete_by_num(&request->packet->vps, PW_STATE, 0, TAG_ANY); + + /* + * Fix the User-Name when proxying, to strip off + * the NT Domain, if we're told to, and a User-Name + * exists, and there's a \\, meaning an NT-Domain + * in the user name, THEN discard the user name. + */ + if (inst->with_ntdomain_hack && + ((challenge = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY)) != NULL) && + ((username = memchr(challenge->vp_octets, '\\', challenge->vp_length)) != NULL)) { + /* + * Wipe out the NT domain. + * + * FIXME: Put it into MS-CHAP-Domain? + */ + username++; /* skip the \\ */ + fr_pair_value_strcpy(challenge, username); + } + + /* + * Remember that in the post-proxy stage, we've got + * to do the work below, AFTER the call to MS-CHAP + * authentication... + */ + return 1; + } +#endif + + /* + * This is a wild & crazy hack. + */ + rcode = process_authenticate(inst->auth_type_mschap, request); + + /* + * Delete MPPE keys & encryption policy. We don't + * want these here. + */ + fix_mppe_keys(handler, data); + + /* + * Take the response from the mschap module, and + * return success or failure, depending on the result. + */ + response = NULL; + if (rcode == RLM_MODULE_OK) { + fr_pair_list_mcopy_by_num(data, &response, &request->reply->vps, PW_MSCHAP2_SUCCESS, VENDORPEC_MICROSOFT, TAG_ANY); + data->code = PW_EAP_MSCHAPV2_SUCCESS; + } else if (inst->send_error) { + fr_pair_list_mcopy_by_num(data, &response, &request->reply->vps, PW_MSCHAP_ERROR, VENDORPEC_MICROSOFT, TAG_ANY); + if (response) { + int n,err,retry; + char buf[34]; + + VERIFY_VP(response); + + RDEBUG2("MSCHAP-Error: %s", response->vp_strvalue); + + /* + * Parse the new challenge out of the + * MS-CHAP-Error, so that if the client + * issues a re-try, we will know which + * challenge value that they used. + */ + n = sscanf(response->vp_strvalue, "%*cE=%d R=%d C=%32s", &err, &retry, &buf[0]); + if (n == 3) { + RDEBUG2("Found new challenge from MS-CHAP-Error: err=%d retry=%d challenge=%s", + err, retry, buf); + fr_hex2bin(data->challenge, 16, buf, strlen(buf)); + } else { + RDEBUG2("Could not parse new challenge from MS-CHAP-Error: %d", n); + } + } + data->code = PW_EAP_MSCHAPV2_FAILURE; + } else { + eap_ds->request->code = PW_EAP_FAILURE; + return 1; + } + + /* + * No response, die. + */ + if (!response) { + REDEBUG("No MS-CHAP2-Success or MS-CHAP-Error was found"); + return 0; + } + + /* + * Compose the response (whatever it is), + * and return it to the over-lying EAP module. + */ + eapmschapv2_compose(inst, handler, response); + fr_pair_list_free(&response); + + 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_mschapv2; +rlm_eap_module_t rlm_eap_mschapv2 = { + .name = "eap_mschapv2", + .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 */ +}; diff --git a/src/modules/rlm_eap/types/rlm_eap_peap/all.mk b/src/modules/rlm_eap/types/rlm_eap_peap/all.mk new file mode 100644 index 0000000..19f51d8 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_peap/all.mk @@ -0,0 +1,10 @@ +TARGETNAME := rlm_eap_peap + +ifneq "$(OPENSSL_LIBS)" "" +TARGET := $(TARGETNAME).a +endif + +SOURCES := $(TARGETNAME).c peap.c + +SRC_INCDIRS := ../../ ../../libeap/ +TGT_PREREQS := libfreeradius-eap.a diff --git a/src/modules/rlm_eap/types/rlm_eap_peap/eap_peap.h b/src/modules/rlm_eap/types/rlm_eap_peap/eap_peap.h new file mode 100644 index 0000000..7b803f8 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_peap/eap_peap.h @@ -0,0 +1,76 @@ +/* + * eap_peap.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_PEAP_H +#define _EAP_PEAP_H + +RCSIDH(eap_peap_h, "$Id$") + +#include "eap_tls.h" +#include <freeradius-devel/soh.h> + +typedef enum { + PEAP_STATUS_INVALID, + PEAP_STATUS_SENT_TLV_SUCCESS, + PEAP_STATUS_SENT_TLV_FAILURE, + PEAP_STATUS_TUNNEL_ESTABLISHED, + PEAP_STATUS_INNER_IDENTITY_REQ_SENT, + PEAP_STATUS_PHASE2_INIT, + PEAP_STATUS_PHASE2, + PEAP_STATUS_WAIT_FOR_SOH_RESPONSE +} peap_status; + +typedef enum { + PEAP_RESUMPTION_NO, + PEAP_RESUMPTION_YES, + PEAP_RESUMPTION_MAYBE +} peap_resumption; + +typedef struct peap_tunnel_t { + VALUE_PAIR *username; + VALUE_PAIR *state; + VALUE_PAIR *accept_vps; + peap_status status; + bool home_access_accept; + int default_method; + bool copy_request_to_tunnel; + bool use_tunneled_reply; + bool proxy_tunneled_request_as_eap; + char const *virtual_server; + bool soh; + char const *soh_virtual_server; + VALUE_PAIR *soh_reply_vps; + peap_resumption session_resumption_state; +} peap_tunnel_t; + + +#define EAP_TLV_SUCCESS (1) +#define EAP_TLV_FAILURE (2) +#define EAP_TLV_ACK_RESULT (3) + +#define PW_EAP_TLV 33 + +/* + * Process the PEAP portion of an EAP-PEAP request. + */ +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 */ diff --git a/src/modules/rlm_eap/types/rlm_eap_peap/peap.c b/src/modules/rlm_eap/types/rlm_eap_peap/peap.c new file mode 100644 index 0000000..a8589ae --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_peap/peap.c @@ -0,0 +1,1316 @@ +/* + * peap.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 2003 Alan DeKok <aland@freeradius.org> + * Copyright 2006 The FreeRADIUS server project + */ + +RCSID("$Id$") +USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ + +#include "eap_peap.h" + +static int setup_fake_request(REQUEST *request, REQUEST *fake, peap_tunnel_t *t); + +/* + * Send protected EAP-Failure + * + * Result-TLV = Failure + */ +static int eappeap_failure(eap_handler_t *handler, tls_session_t *tls_session) +{ + uint8_t tlv_packet[11]; + REQUEST *request = handler->request; + + RDEBUG2("FAILURE"); + + tlv_packet[0] = PW_EAP_REQUEST; + tlv_packet[1] = handler->eap_ds->response->id +1; + tlv_packet[2] = 0; + tlv_packet[3] = 11; /* length of this packet */ + tlv_packet[4] = PW_EAP_TLV; + tlv_packet[5] = 0x80; + tlv_packet[6] = EAP_TLV_ACK_RESULT; + tlv_packet[7] = 0; + tlv_packet[8] = 2; /* length of the data portion */ + tlv_packet[9] = 0; + tlv_packet[10] = EAP_TLV_FAILURE; + + (tls_session->record_plus)(&tls_session->clean_in, tlv_packet, 11); + + /* + * FIXME: Check the return code. + */ + tls_handshake_send(request, tls_session); + + return 1; +} + + +/* + * Send protected EAP-Success + * + * Result-TLV = Success + */ +static int eappeap_success(eap_handler_t *handler, tls_session_t *tls_session) +{ + uint8_t tlv_packet[11]; + REQUEST *request = handler->request; + + RDEBUG2("SUCCESS"); + + tlv_packet[0] = PW_EAP_REQUEST; + tlv_packet[1] = handler->eap_ds->response->id +1; + tlv_packet[2] = 0; + tlv_packet[3] = 11; /* length of this packet */ + tlv_packet[4] = PW_EAP_TLV; + tlv_packet[5] = 0x80; /* mandatory AVP */ + tlv_packet[6] = EAP_TLV_ACK_RESULT; + tlv_packet[7] = 0; + tlv_packet[8] = 2; /* length of the data portion */ + tlv_packet[9] = 0; + tlv_packet[10] = EAP_TLV_SUCCESS; + + (tls_session->record_plus)(&tls_session->clean_in, tlv_packet, 11); + + /* + * FIXME: Check the return code. + */ + tls_handshake_send(request, tls_session); + + return 1; +} + + +static int eappeap_identity(eap_handler_t *handler, tls_session_t *tls_session) +{ + eap_packet_raw_t eap_packet; + + eap_packet.code = PW_EAP_REQUEST; + eap_packet.id = handler->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; + + (tls_session->record_plus)(&tls_session->clean_in, + &eap_packet, sizeof(eap_packet)); + + tls_handshake_send(handler->request, tls_session); + (tls_session->record_init)(&tls_session->clean_in); + + return 1; +} + +/* + * Send an MS SoH request + */ +static int eappeap_soh(eap_handler_t *handler, tls_session_t *tls_session) +{ + uint8_t tlv_packet[20]; + + tlv_packet[0] = 254; /* extended type */ + + tlv_packet[1] = 0; + tlv_packet[2] = 0x01; /* ms vendor */ + tlv_packet[3] = 0x37; + + tlv_packet[4] = 0; /* ms soh eap */ + tlv_packet[5] = 0; + tlv_packet[6] = 0; + tlv_packet[7] = 0x21; + + tlv_packet[8] = 0; /* vendor-spec tlv */ + tlv_packet[9] = 7; + + tlv_packet[10] = 0; + tlv_packet[11] = 8; /* payload len */ + + tlv_packet[12] = 0; /* ms vendor */ + tlv_packet[13] = 0; + tlv_packet[14] = 0x01; + tlv_packet[15] = 0x37; + + tlv_packet[16] = 0; + tlv_packet[17] = 2; + tlv_packet[18] = 0; + tlv_packet[19] = 0; + + (tls_session->record_plus)(&tls_session->clean_in, tlv_packet, 20); + tls_handshake_send(handler->request, tls_session); + return 1; +} + +static void eapsoh_verify(REQUEST *request, RADIUS_PACKET *packet, + uint8_t const *data, unsigned int data_len) { + + VALUE_PAIR *vp; + uint8_t eap_method_base; + uint32_t eap_vendor; + uint32_t eap_method; + int rv; + + vp = fr_pair_make(packet, &packet->vps, "SoH-Supported", "no", T_OP_EQ); + if (data && data[0] == PW_EAP_NAK) { + RDEBUG("SoH - client NAKed"); + return; + } + + if (!data || data_len < 8) { + RDEBUG("SoH - eap payload too short"); + return; + } + + eap_method_base = *data++; + if (eap_method_base != 254) { + RDEBUG("SoH - response is not extended EAP: %i", eap_method_base); + return; + } + + eap_vendor = soh_pull_be_24(data); data += 3; + if (eap_vendor != 0x137) { + RDEBUG("SoH - extended eap vendor %08x is not Microsoft", eap_vendor); + return; + } + + eap_method = soh_pull_be_32(data); data += 4; + if (eap_method != 0x21) { + RDEBUG("SoH - response eap type %08x is not EAP-SoH", eap_method); + return; + } + + + rv = soh_verify(request, data, data_len - 8); + if (rv<0) { + RDEBUG("SoH - error decoding payload: %s", fr_strerror()); + } else { + vp->vp_integer = 1; + } +} + +/* + * Verify the tunneled EAP message. + */ +static int eapmessage_verify(REQUEST *request, + uint8_t const *data, unsigned int data_len, int peap_version) +{ + eap_packet_raw_t const *eap_packet = (eap_packet_raw_t const *) data; + eap_type_t eap_method; + + /* + * Hack for now. + */ + if (peap_version == 1) return 1; + + /* + * No data, OR only 1 byte of EAP type. + */ + if (!data || (data_len == 0) || + ((data_len <= 1) && (data[0] != PW_EAP_IDENTITY))) { + return 0; + } + + eap_method = *data; + switch (eap_method) { + case PW_EAP_IDENTITY: + if (data_len == 1) { + RDEBUG2("Identity - "); + return 1; + } + RDEBUG2("Identity - %*s", + data_len - 1, data + 1); + return 1; + + /* + * If the first byte of the packet is + * EAP-Response, and the EAP data is a TLV, + * then it looks OK... + */ + case PW_EAP_RESPONSE: + if (eap_packet->data[0] == PW_EAP_TLV) { + RDEBUG2("Received EAP-TLV response"); + return 1; + } + RDEBUG2("Received unexpected EAP-Response, rejecting the session."); + break; + + + /* + * We normally do Microsoft MS-CHAPv2 (26), versus + * Cisco MS-CHAPv2 (29). + */ + case PW_EAP_MSCHAPV2: + default: + RDEBUG2("EAP method %s (%d)", eap_type2name(eap_method), + eap_method); + return 1; + } + + return 0; +} + +/* + * Convert a pseudo-EAP packet to a list of VALUE_PAIR's. + */ +static VALUE_PAIR *eap2vp(UNUSED REQUEST *request, RADIUS_PACKET *packet, + EAP_DS *eap_ds, + uint8_t const *data, size_t data_len, int peap_version) +{ + size_t total; + uint8_t *p; + VALUE_PAIR *vp = NULL, *head = NULL; + vp_cursor_t cursor; + + if (data_len > 65535) return NULL; /* paranoia */ + + vp = fr_pair_afrom_num(packet, PW_EAP_MESSAGE, 0); + if (!vp) { + return NULL; + } + + total = data_len; + if (total > 249) total = 249; + + if (peap_version == 0) { + /* + * Hand-build an EAP packet from the crap in PEAP version 0. + */ + vp->vp_length = EAP_HEADER_LEN + total; + vp->vp_octets = p = talloc_array(vp, uint8_t, vp->vp_length); + + p[0] = PW_EAP_RESPONSE; + p[1] = eap_ds->response->id; + p[2] = (data_len + EAP_HEADER_LEN) >> 8; + p[3] = (data_len + EAP_HEADER_LEN) & 0xff; + + memcpy(p + EAP_HEADER_LEN, data, total); + + } else { /* peapv1 */ + vp->vp_length = total; + vp->vp_octets = p = talloc_array(vp, uint8_t, vp->vp_length); + memcpy(p, data, total); + } + + fr_cursor_init(&cursor, &head); + fr_cursor_insert(&cursor, vp); + while (total < data_len) { + vp = fr_pair_afrom_num(packet, PW_EAP_MESSAGE, 0); + if (!vp) { + fr_pair_list_free(&head); + return NULL; + } + + fr_pair_value_memcpy(vp, data + total, (data_len - total)); + + total += vp->vp_length; + + fr_cursor_insert(&cursor, vp); + } + + return head; +} + + +/* + * Convert a list of VALUE_PAIR's to an EAP packet, through the + * simple expedient of dumping the EAP message + */ +static int vp2eap(REQUEST *request, tls_session_t *tls_session, VALUE_PAIR *vp) +{ + rad_assert(vp != NULL); + VALUE_PAIR *this; + vp_cursor_t cursor; + size_t header = EAP_HEADER_LEN; + + if (tls_session->peap_flag > 0) header = 0; + + /* + * Skip the id, code, and length. Just write the EAP + * type & data to the client. + */ +#ifndef NDEBUG + if ((rad_debug_lvl > 2) && fr_log_fp) { + size_t i, total, start = header; + total = 0; + + for (this = fr_cursor_init(&cursor, &vp); this; this = fr_cursor_next(&cursor)) { + for (i = start; i < vp->vp_length; i++) { + if ((total & 0x0f) == 0) { + fprintf(fr_log_fp, " PEAP tunnel data out %04x: ", (int) total); + } + fprintf(fr_log_fp, "%02x ", vp->vp_octets[i]); + + if ((total & 0x0f) == 0x0f) { + fprintf(fr_log_fp, "\n"); + } + + total++; + } + + start = 0; + } + + if ((total & 0x0f) != 0) { + fprintf(fr_log_fp, "\n"); + } + } +#endif + + /* + * Send the EAP data in the first attribute, WITHOUT the + * header. + */ + (tls_session->record_plus)(&tls_session->clean_in, vp->vp_octets + header, vp->vp_length - header); + + /* + * Send the rest of the EAP data, but skipping the first VP. + */ + fr_cursor_init(&cursor, &vp); + for (this = fr_cursor_next(&cursor); + this; + this = fr_cursor_next(&cursor)) { + (tls_session->record_plus)(&tls_session->clean_in, this->vp_octets, this->vp_length); + } + + tls_handshake_send(request, tls_session); + + return 1; +} + + +/* + * See if there's a TLV in the response. + */ +static int eappeap_check_tlv(REQUEST *request, uint8_t const *data, + size_t data_len) +{ + eap_packet_raw_t const *eap_packet = (eap_packet_raw_t const *) data; + + if (data_len < 11) return 0; + + /* + * Look for success or failure. + */ + if ((eap_packet->code == PW_EAP_RESPONSE) && + (eap_packet->data[0] == PW_EAP_TLV)) { + if (data[10] == EAP_TLV_SUCCESS) { + return 1; + } + + if (data[10] == EAP_TLV_FAILURE) { + RDEBUG2("Client rejected our response. The password is probably incorrect"); + return 0; + } + } + + RDEBUG("Unknown TLV %02x", data[10]); + + return 0; +} + + +/* + * Use a reply packet to determine what to do. + */ +static rlm_rcode_t CC_HINT(nonnull) process_reply(eap_handler_t *handler, tls_session_t *tls_session, + REQUEST *request, RADIUS_PACKET *reply) +{ + rlm_rcode_t rcode = RLM_MODULE_REJECT; + VALUE_PAIR *vp; + peap_tunnel_t *t = tls_session->opaque; + + if ((rad_debug_lvl > 0) && fr_log_fp) { + RDEBUG("Got tunneled reply RADIUS code %d", reply->code); + rdebug_pair_list(L_DBG_LVL_1, request, reply->vps, NULL); + } + + switch (reply->code) { + case PW_CODE_ACCESS_ACCEPT: + RDEBUG2("Tunneled authentication was successful"); + tls_session->authentication_success = true; + t->status = PEAP_STATUS_SENT_TLV_SUCCESS; + eappeap_success(handler, tls_session); + rcode = RLM_MODULE_HANDLED; + + /* + * If we've been told to use the attributes from + * the reply, then do so. + * + * WARNING: This may leak information about the + * tunneled user! + */ + if (t->use_tunneled_reply) { + RDEBUG2("Saving tunneled attributes for later"); + + /* + * 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; + + case PW_CODE_ACCESS_REJECT: + RDEBUG2("Tunneled authentication was rejected"); + t->status = PEAP_STATUS_SENT_TLV_FAILURE; + eappeap_failure(handler, tls_session); + rcode = RLM_MODULE_HANDLED; + break; + + case PW_CODE_ACCESS_CHALLENGE: + RDEBUG2("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); + + /* + * PEAP takes only EAP-Message attributes inside + * of the tunnel. Any Reply-Message in the + * Access-Challenge is ignored. + */ + vp = NULL; + fr_pair_list_mcopy_by_num(t, &vp, &reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY); + + /* + * Handle EAP-MSCHAP-V2, where Access-Accept's + * from the home server may contain MS-CHAP2-Success, + * which the module turns into challenges, so that + * the client may respond to the challenge with + * an "ack" packet. + */ + if (t->home_access_accept && t->use_tunneled_reply) { + RDEBUG2("Saving tunneled attributes for later"); + + /* + * 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_MESSAGE_AUTHENTICATOR, 0, TAG_ANY); + + rad_assert(!t->accept_vps); + fr_pair_list_mcopy_by_num(t, &t->accept_vps, &reply->vps, 0, 0, TAG_ANY); + rad_assert(!reply->vps); + } + + /* + * Handle the ACK, by tunneling any necessary reply + * VP's back to the client. + */ + if (vp) { + vp2eap(request, tls_session, vp); + fr_pair_list_free(&vp); + } + + rcode = RLM_MODULE_HANDLED; + break; + + default: + RDEBUG2("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code); + rcode = RLM_MODULE_REJECT; + break; + } + + return rcode; +} + +#ifdef WITH_PROXY +/* + * Do post-proxy processing, + */ +static int CC_HINT(nonnull) eappeap_postproxy(eap_handler_t *handler, void *data) +{ + int rcode; + tls_session_t *tls_session = (tls_session_t *) data; + REQUEST *fake, *request = handler->request; + + RDEBUG2("Passing reply from proxy back into the tunnel"); + + /* + * If there was a fake request associated with the proxied + * request, do more processing of it. + */ + fake = (REQUEST *) request_data_get(handler->request, + handler->request->proxy, + REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK); + + /* + * Do the callback, if it exists, and if it was a success. + */ + if (fake && (handler->request->proxy_reply->code == PW_CODE_ACCESS_ACCEPT)) { + peap_tunnel_t *t = tls_session->opaque; + + t->home_access_accept = true; + + /* + * Terrible hacks. + */ + rad_assert(!fake->packet); + fake->packet = talloc_steal(fake, request->proxy); + fake->packet->src_ipaddr = request->packet->src_ipaddr; + request->proxy = NULL; + + rad_assert(!fake->reply); + fake->reply = talloc_steal(fake, request->proxy_reply); + request->proxy_reply = NULL; + + if ((rad_debug_lvl > 0) && fr_log_fp) { + fprintf(fr_log_fp, "server %s {\n", fake->server); + } + + fake->reply->code = PW_CODE_ACCESS_ACCEPT; + + /* + * Perform a post-auth stage, which will get the EAP + * handler, too... + */ + fake->options &= ~RAD_REQUEST_OPTION_PROXY_EAP; + RDEBUG2("Passing reply back for EAP-MS-CHAP-V2"); + process_post_proxy(0, fake); + + /* + * FIXME: If rcode returns fail, do something + * intelligent... + */ + rcode = rad_postauth(fake); + + if ((rad_debug_lvl > 0) && fr_log_fp) { + fprintf(fr_log_fp, "} # server %s\n", fake->server); + + RDEBUG("Final reply from tunneled session code %d", fake->reply->code); + rdebug_pair_list(L_DBG_LVL_1, request, fake->reply->vps, NULL); + } + + /* + * Terrible hacks. + */ + request->proxy = talloc_steal(request, fake->packet); + fake->packet = NULL; + request->proxy_reply = talloc_steal(request, fake->reply); + fake->reply = NULL; + + /* + * And we're done with this request. + */ + + switch (rcode) { + case RLM_MODULE_FAIL: + talloc_free(fake); + eaptls_fail(handler, 0); + return 0; + + default: /* Don't Do Anything */ + RDEBUG2("Got reply %d", request->proxy_reply->code); + break; + } + } + talloc_free(fake); /* robust if !fake */ + + /* + * If there was no EAP-Message in the reply packet, then + * we know that we're supposed to re-run the "authenticate" + * stage, in order to get the right kind of handling... + */ + + /* + * Process the reply from the home server. + */ + + rcode = process_reply(handler, tls_session, handler->request, + handler->request->proxy_reply); + + /* + * The proxy code uses the reply from the home server as + * the basis for the reply to the NAS. We don't want that, + * so we toss it, after we've had our way with it. + */ + fr_pair_list_free(&handler->request->proxy_reply->vps); + + switch (rcode) { + case RLM_MODULE_REJECT: + RDEBUG2("Reply was rejected"); + eaptls_fail(handler, 0); + return 0; + + case RLM_MODULE_HANDLED: + RDEBUG2("Reply was handled"); + eaptls_request(handler->eap_ds, tls_session); + request->proxy_reply->code = PW_CODE_ACCESS_CHALLENGE; + return 1; + + case RLM_MODULE_OK: + RDEBUG2("Reply was OK"); + + /* + * Success: Automatically return MPPE keys. + */ + return eaptls_success(handler, 0); + + default: + RDEBUG2("Reply was unknown"); + break; + } + + eaptls_fail(handler, 0); + return 0; +} +#endif + + +static char const *peap_state(peap_tunnel_t *t) +{ + switch (t->status) { + case PEAP_STATUS_TUNNEL_ESTABLISHED: + return "TUNNEL ESTABLISHED"; + + case PEAP_STATUS_WAIT_FOR_SOH_RESPONSE: + return "WAITING FOR SOH RESPONSE"; + + case PEAP_STATUS_INNER_IDENTITY_REQ_SENT: + return "WAITING FOR INNER IDENTITY"; + + case PEAP_STATUS_SENT_TLV_SUCCESS: + return "send tlv success"; + + case PEAP_STATUS_SENT_TLV_FAILURE: + return "send tlv failure"; + + case PEAP_STATUS_PHASE2_INIT: + return "phase2_init"; + + case PEAP_STATUS_PHASE2: + return "phase2"; + + default: + break; + } + return "?"; +} + +static void print_tunneled_data(uint8_t const *data, size_t data_len) +{ + size_t i; + + if ((rad_debug_lvl > 2) && fr_log_fp) { + for (i = 0; i < data_len; i++) { + if ((i & 0x0f) == 0) fprintf(fr_log_fp, " PEAP tunnel data in %02x: ", (int) i); + + fprintf(fr_log_fp, "%02x ", data[i]); + + if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n"); + } + if ((data_len & 0x0f) != 0) fprintf(fr_log_fp, "\n"); + } +} + + +/* + * Process the pseudo-EAP contents of the tunneled data. + */ +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; + VALUE_PAIR *vp; + rlm_rcode_t rcode = RLM_MODULE_REJECT; + uint8_t const *data; + unsigned int data_len; + size_t header = 0; + + REQUEST *request = handler->request; + EAP_DS *eap_ds = handler->eap_ds; + + /* + * Just look at the buffer directly, without doing + * record_minus. This lets us avoid another data copy. + */ + data_len = tls_session->clean_out.used; + tls_session->clean_out.used = 0; + data = tls_session->clean_out.data; + + RDEBUG2("PEAP state %s", peap_state(t)); + + if ((t->status != PEAP_STATUS_TUNNEL_ESTABLISHED) && + !eapmessage_verify(request, data, data_len, tls_session->peap_flag)) { + REDEBUG("Tunneled data is invalid"); + if (rad_debug_lvl > 2) print_tunneled_data(data, data_len); + return RLM_MODULE_REJECT; + } + + if (tls_session->peap_flag > 0) header = EAP_HEADER_LEN; + + switch (t->status) { + case PEAP_STATUS_TUNNEL_ESTABLISHED: + /* FIXME: should be no data in the buffer here, check & assert? */ + + if (SSL_session_reused(tls_session->ssl)) { + RDEBUG2("Skipping Phase2 because of session resumption"); + t->session_resumption_state = PEAP_RESUMPTION_YES; + if (t->soh) { + t->status = PEAP_STATUS_WAIT_FOR_SOH_RESPONSE; + RDEBUG2("Requesting SoH from client"); + eappeap_soh(handler, tls_session); + return RLM_MODULE_HANDLED; + } + /* we're good, send success TLV */ + t->status = PEAP_STATUS_SENT_TLV_SUCCESS; + eappeap_success(handler, tls_session); + + } else { + /* send an identity request */ + t->session_resumption_state = PEAP_RESUMPTION_NO; + t->status = PEAP_STATUS_INNER_IDENTITY_REQ_SENT; + tls_session->session_not_resumed = true; + eappeap_identity(handler, tls_session); + } + return RLM_MODULE_HANDLED; + + case PEAP_STATUS_INNER_IDENTITY_REQ_SENT: + /* we're expecting an identity response */ + if (data[header] != PW_EAP_IDENTITY) { + REDEBUG("Expected EAP-Identity, got something else"); + return RLM_MODULE_REJECT; + } + + /* + * Save it for later. + */ + t->username = fr_pair_make(t, NULL, "User-Name", NULL, T_OP_EQ); + rad_assert(t->username != NULL); + + fr_pair_value_bstrncpy(t->username, data + header + 1, data_len - header - 1); + + RDEBUG("Got inner identity '%s'", t->username->vp_strvalue); + if (t->soh) { + t->status = PEAP_STATUS_WAIT_FOR_SOH_RESPONSE; + RDEBUG2("Requesting SoH from client"); + eappeap_soh(handler, tls_session); + return RLM_MODULE_HANDLED; + } + t->status = PEAP_STATUS_PHASE2_INIT; + break; + + case PEAP_STATUS_WAIT_FOR_SOH_RESPONSE: + fake = request_alloc_fake(request); + rad_assert(!fake->packet->vps); + eapsoh_verify(fake, fake->packet, data + header, data_len - header); + setup_fake_request(request, fake, t); + + if (t->soh_virtual_server) { + fake->server = t->soh_virtual_server; + } + RDEBUG("Sending SoH request to server %s", fake->server ? fake->server : "NULL"); + rad_virtual_server(fake); + + if (fake->reply->code != PW_CODE_ACCESS_ACCEPT) { + RDEBUG2("SoH was rejected"); + talloc_free(fake); + t->status = PEAP_STATUS_SENT_TLV_FAILURE; + eappeap_failure(handler, tls_session); + return RLM_MODULE_HANDLED; + } + + /* save the SoH VPs */ + rad_assert(!t->soh_reply_vps); + fr_pair_list_mcopy_by_num(t, &t->soh_reply_vps, &fake->reply->vps, 0, 0, TAG_ANY); + rad_assert(!fake->reply->vps); + talloc_free(fake); + + if (t->session_resumption_state == PEAP_RESUMPTION_YES) { + /* we're good, send success TLV */ + t->status = PEAP_STATUS_SENT_TLV_SUCCESS; + eappeap_success(handler, tls_session); + return RLM_MODULE_HANDLED; + } + + t->status = PEAP_STATUS_PHASE2_INIT; + break; + + + /* + * If we authenticated the user, then it's OK. + */ + case PEAP_STATUS_SENT_TLV_SUCCESS: + if (eappeap_check_tlv(request, data + header, data_len - header)) { + RDEBUG2("Success"); + return RLM_MODULE_OK; + } + + /* + * Otherwise, the client rejected the session + * resumption. If the session is being re-used, + * we need to do a full authentication. + * + * We do this by sending an EAP-Identity request + * inside of the PEAP tunnel. + */ + if (t->session_resumption_state == PEAP_RESUMPTION_YES) { + RDEBUG2("Client rejected session resumption. Re-starting full authentication"); + + /* + * Mark session resumption status. + */ + t->status = PEAP_STATUS_INNER_IDENTITY_REQ_SENT; + t->session_resumption_state = PEAP_RESUMPTION_NO; + + eappeap_identity(handler, tls_session); + return RLM_MODULE_HANDLED; + } + + REDEBUG("We sent a success, but the client did not agree"); + return RLM_MODULE_REJECT; + + /* + * Supplicant ACKs our failure. + */ + case PEAP_STATUS_SENT_TLV_FAILURE: + RINDENT(); + REDEBUG("The users session was previously rejected: returning reject (again.)"); + RDEBUG("This means you need to read the PREVIOUS messages in the debug output"); + RDEBUG("to find out the reason why the user was rejected"); + RDEBUG("Look for \"reject\" or \"fail\". Those earlier messages will tell you"); + RDEBUG("what went wrong, and how to fix the problem"); + REXDENT(); + + return RLM_MODULE_REJECT; + + case PEAP_STATUS_PHASE2_INIT: + RDEBUG("In state machine in phase2 init?"); + + case PEAP_STATUS_PHASE2: + break; + + default: + REDEBUG("Unhandled state in peap"); + return RLM_MODULE_REJECT; + } + + fake = request_alloc_fake(request); + + rad_assert(!fake->packet->vps); + + switch (t->status) { + /* + * If we're in PHASE2_INIT, the phase2 method hasn't been + * sent an Identity packet yet; do so from the stored + * username and this will kick off the phase2 eap method + */ + + case PEAP_STATUS_PHASE2_INIT: { + size_t len = t->username->vp_length + EAP_HEADER_LEN + 1; + uint8_t *q; + + t->status = PEAP_STATUS_PHASE2; + + vp = fr_pair_afrom_num(fake->packet, PW_EAP_MESSAGE, 0); + vp->vp_length = len; + vp->vp_octets = q = talloc_array(vp, uint8_t, vp->vp_length); + + q[0] = PW_EAP_RESPONSE; + q[1] = eap_ds->response->id; + q[2] = (len >> 8) & 0xff; + q[3] = len & 0xff; + q[4] = PW_EAP_IDENTITY; + + memcpy(q + EAP_HEADER_LEN + 1, + t->username->vp_strvalue, t->username->vp_length); + + fr_pair_add(&fake->packet->vps, vp); + + if (t->default_method != 0) { + RDEBUG2("Setting default EAP type for tunneled EAP session"); + vp = fr_pair_make(fake, &fake->config, "EAP-Type", "0", T_OP_EQ); + vp->vp_integer = t->default_method; + } + break; } + + case PEAP_STATUS_PHASE2: + fake->packet->vps = eap2vp(request, fake->packet, + eap_ds, data, data_len, tls_session->peap_flag); + if (!fake->packet->vps) { + talloc_free(fake); + RDEBUG2("Unable to convert tunneled EAP packet to internal server data structures"); + return RLM_MODULE_REJECT; + } + break; + + default: + REDEBUG("Invalid state change in PEAP"); + return RLM_MODULE_REJECT; + } + + RDEBUG2("Got tunneled request"); + rdebug_pair_list(L_DBG_LVL_2, request, fake->packet->vps, NULL); + + /* + * Update other items in the REQUEST data structure. + */ + if (!t->username) { + /* + * There's no User-Name in the tunneled session, + * so we add one here, by pulling it out of the + * EAP-Identity packet. + */ + if ((data[header] == PW_EAP_IDENTITY) && (data_len > (1 + header))) { + t->username = fr_pair_make(t, NULL, "User-Name", NULL, T_OP_EQ); + rad_assert(t->username != NULL); + + fr_pair_value_bstrncpy(t->username, data + header + 1, data_len - header - 1); + + RDEBUG2("Got tunneled identity of %s", t->username->vp_strvalue); + + /* + * If there's a default EAP type, + * set it here. + */ + if (t->default_method != 0) { + RDEBUG2("Setting default EAP type for tunneled EAP session"); + vp = fr_pair_make(fake, &fake->config, "EAP-Type", "0", T_OP_EQ); + vp->vp_integer = t->default_method; + } + } + } /* else there WAS a t->username */ + + setup_fake_request(request, fake, t); + + 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 */ + + if (fake->server) { + RDEBUG2("Sending tunneled request to %s", fake->server); + } else { + RDEBUG2("Sending tunnelled request"); + } + rdebug_pair_list(L_DBG_LVL_2, request, fake->packet->vps, NULL); + + /* + * Call authentication recursively, which will + * do PAP, CHAP, MS-CHAP, etc. + */ + rad_virtual_server(fake); + + /* + * Note that we don't do *anything* with the reply + * attributes. + */ + RDEBUG2("Got tunneled reply code %d", fake->reply->code); + rdebug_pair_list(L_DBG_LVL_2, request, fake->reply->vps, NULL); + + /* + * Decide what to do with the reply. + */ + switch (fake->reply->code) { + case 0: /* No reply code, must be proxied... */ +#ifdef WITH_PROXY + vp = fr_pair_find_by_num(fake->config, PW_PROXY_TO_REALM, 0, TAG_ANY); + + if (vp) { + eap_tunnel_data_t *tunnel; + bool proxy_as_eap = t->proxy_tunneled_request_as_eap; + VALUE_PAIR *flag = fr_pair_find_by_num(fake->config, PW_PROXY_TUNNELED_REQUEST_AS_EAP, 0, TAG_ANY); + + if (flag) proxy_as_eap = flag->vp_integer; + + /* + * The tunneled request was NOT handled, + * it has to be proxied. This means that + * the "authenticate" stage was never + * performed. + * + * If we are told to NOT proxy the + * tunneled request as EAP, then this + * means that we've got to decode it, + * which means that we MUST run the + * "authenticate" portion by hand, here. + * + * Once the tunneled EAP session is ALMOST + * done, THEN we proxy it... + */ + if (!proxy_as_eap) { + fake->options |= RAD_REQUEST_OPTION_PROXY_EAP; + + /* + * Hmm... should we check for + * 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(auth_type_eap, fake); + if (rcode == RLM_MODULE_OK) { + /* + * Authentication succeeded! Rah! + */ + fake->reply->code = PW_CODE_ACCESS_ACCEPT; + goto do_process; + } + + if (rcode != RLM_MODULE_HANDLED) { + RDEBUG("Can't handle the return code %d", rcode); + rcode = RLM_MODULE_REJECT; + goto done; + } + + /* + * The module decided it wasn't + * done. Handle it like normal. + */ + if ((fake->options & RAD_REQUEST_OPTION_PROXY_EAP) == 0) { + RDEBUG2("Cancelling proxy to realm %s until the tunneled EAP session " + "has been established", vp->vp_strvalue); + goto do_process; + } + + /* + * The module has decoded the + * EAP-Message into another set + * of attributes. + */ + fr_pair_delete_by_num(&fake->packet->vps, + PW_EAP_MESSAGE, 0, TAG_ANY); + } + + RDEBUG2("Tunnelled authentication will be proxied to %s", vp->vp_strvalue); + + /* + * Tell the original request that it's going + * to be proxied. + */ + fr_pair_list_mcopy_by_num(request, &request->config, + &fake->config, + PW_PROXY_TO_REALM, 0, TAG_ANY); + + /* + * Seed the proxy packet with the + * tunneled request. + */ + rad_assert(!request->proxy); + request->proxy = talloc_steal(request, fake->packet); + memset(&request->proxy->src_ipaddr, 0, + sizeof(request->proxy->src_ipaddr)); + memset(&request->proxy->dst_ipaddr, 0, + sizeof(request->proxy->dst_ipaddr)); + request->proxy->src_port = 0; + request->proxy->dst_port = 0; + fake->packet = NULL; + rad_free(&fake->reply); + fake->reply = NULL; + + /* + * Set up the callbacks for the tunnel + */ + tunnel = talloc_zero(request, eap_tunnel_data_t); + tunnel->tls_session = tls_session; + tunnel->callback = eappeap_postproxy; + + /* + * Associate the callback with the request. + */ + rcode = request_data_add(request, + request->proxy, + REQUEST_DATA_EAP_TUNNEL_CALLBACK, + tunnel, false); + rad_assert(rcode == 0); + + /* + * We're not proxying it as EAP, so we've got + * to do the callback later. + */ + if ((fake->options & RAD_REQUEST_OPTION_PROXY_EAP) != 0) { + RDEBUG2("Remembering to do EAP-MS-CHAP-V2 post-proxy"); + + /* + * rlm_eap.c has taken care of associating + * the handler with the fake request. + * + * So we associate the fake request with + * this request. + */ + rcode = request_data_add(request, request->proxy, + REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK, + fake, true); + rad_assert(rcode == 0); + + /* + * Do NOT free the fake request! + */ + return RLM_MODULE_UPDATED; + } + + /* + * Didn't authenticate the packet, but + * we're proxying it. + */ + rcode = RLM_MODULE_UPDATED; + + } else +#endif /* WITH_PROXY */ + { + REDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", fake->reply->code); + rcode = RLM_MODULE_REJECT; + } + break; + + default: +#ifdef WITH_PROXY + do_process: +#endif + rcode = process_reply(handler, tls_session, request, + fake->reply); + break; + } + +#ifdef WITH_PROXY + done: +#endif + talloc_free(fake); + + return rcode; +} + +static int CC_HINT(nonnull) setup_fake_request(REQUEST *request, REQUEST *fake, peap_tunnel_t *t) { + + VALUE_PAIR *vp; + + /* + * Tell the request that it's a fake one. + */ + fr_pair_make(fake->packet, &fake->packet->vps, "Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ); + + if (t->username) { + vp = fr_pair_list_copy(fake->packet, t->username); + fr_pair_add(&fake->packet->vps, vp); + fake->username = vp; + RDEBUG2("Setting User-Name to %s", fake->username->vp_strvalue); + } else { + RDEBUG2("No tunnel username (SSL resumption?)"); + } + + + /* + * 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 this is set, we copy SOME of the request attributes + * from outside of the tunnel to inside of the tunnel. + * + * We copy ONLY those attributes which do NOT already + * exist in the tunneled request. + * + * This code is copied from ../rlm_eap_ttls/ttls.c + */ + if (t->copy_request_to_tunnel) { + VALUE_PAIR *copy; + 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); + } + } + + return 0; +} diff --git a/src/modules/rlm_eap/types/rlm_eap_peap/rlm_eap_peap.c b/src/modules/rlm_eap/types/rlm_eap_peap/rlm_eap_peap.c new file mode 100644 index 0000000..d9f850c --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_peap/rlm_eap_peap.c @@ -0,0 +1,429 @@ +/* + * rlm_eap_peap.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 2003 Alan DeKok <aland@freeradius.org> + * Copyright 2006 The FreeRADIUS server project + */ + +RCSID("$Id$") + +#include "eap_peap.h" + +typedef struct rlm_eap_peap_t { + char const *tls_conf_name; //!< TLS configuration. + fr_tls_server_conf_t *tls_conf; + char const *default_method_name; //!< Default tunneled EAP type. + int default_method; + + 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. + + bool copy_request_to_tunnel; //!< Use SOME of the request attributes from outside of the + //!< tunneled session in the tunneled request. +#ifdef WITH_PROXY + bool proxy_tunneled_request_as_eap; //!< Proxy tunneled session as EAP, or as de-capsulated + //!< protocol. +#endif + char const *virtual_server; //!< Virtual server for inner tunnel session. + + bool soh; //!< Do we do SoH request? + char const *soh_virtual_server; + bool req_client_cert; //!< Do we do require a client cert? +} rlm_eap_peap_t; + + +static CONF_PARSER module_config[] = { + { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, tls_conf_name), NULL }, + + { "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" }, + +#ifdef WITH_PROXY + { "proxy_tunneled_request_as_eap", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, proxy_tunneled_request_as_eap), "yes" }, +#endif + + { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, virtual_server), NULL }, + + { "soh", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, soh), "no" }, + + { "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 +}; + + +/* + * Attach the module. + */ +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; + + /* + * Parse the configuration attributes. + */ + if (cf_section_parse(cs, inst, module_config) < 0) { + 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. + */ + inst->default_method = eap_name2type(inst->default_method_name); + if (inst->default_method < 0) { + ERROR("rlm_eap_peap: 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_peap: Failed initializing SSL context"); + 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; +} + +/* + * Allocate the PEAP per-session data + */ +static peap_tunnel_t *peap_alloc(TALLOC_CTX *ctx, rlm_eap_peap_t *inst) +{ + peap_tunnel_t *t; + + t = talloc_zero(ctx, peap_tunnel_t); + + t->default_method = inst->default_method; + t->copy_request_to_tunnel = inst->copy_request_to_tunnel; + t->use_tunneled_reply = inst->use_tunneled_reply; +#ifdef WITH_PROXY + t->proxy_tunneled_request_as_eap = inst->proxy_tunneled_request_as_eap; +#endif + t->virtual_server = inst->virtual_server; + t->soh = inst->soh; + t->soh_virtual_server = inst->soh_virtual_server; + t->session_resumption_state = PEAP_RESUMPTION_MAYBE; + + return t; +} + +/* + * 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 status; + tls_session_t *ssn; + rlm_eap_peap_t *inst; + VALUE_PAIR *vp; + bool client_cert; + REQUEST *request = handler->request; + + inst = type_arg; + + handler->tls = true; + + /* + * Check if we need a client certificate. + */ + + /* + * 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; + } + + /* + * Allow TLS 1.3, it works. + */ + ssn = eaptls_session(handler, inst->tls_conf, client_cert, true); + if (!ssn) { + return 0; + } + + handler->opaque = ((void *)ssn); + + /* + * Set the label to a fixed string. For TLS 1.3, the + * label is the same for all TLS-based EAP methods. If + * the client is using TLS 1.3, then eaptls_success() + * will over-ride this label with the correct label for + * TLS 1.3. + */ + ssn->label = "client EAP encryption"; + + /* + * As it is a poorly designed protocol, PEAP uses + * bits in the TLS header to indicate PEAP + * version numbers. For now, we only support + * PEAP version 0, so it doesn't matter too much. + * However, if we support later versions of PEAP, + * we will need this flag to indicate which + * version we're currently dealing with. + */ + ssn->peap_flag = 0x00; + + /* + * PEAP version 0 requires 'include_length = no', + * so rather than hoping the user figures it out, + * we force it here. + */ + ssn->length_flag = false; + + /* + * TLS session initialization is over. Now handle TLS + * related handshaking or application data. + */ + status = eaptls_start(handler->eap_ds, ssn->peap_flag); + if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) { + REDEBUG("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } else { + RDEBUG3("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } + if (status == 0) return 0; + + /* + * The next stage to process the packet. + */ + handler->stage = PROCESS; + + 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; + int ret = 0; + fr_tls_status_t status; + rlm_eap_peap_t *inst = (rlm_eap_peap_t *) arg; + tls_session_t *tls_session = (tls_session_t *) handler->opaque; + peap_tunnel_t *peap = tls_session->opaque; + REQUEST *request = handler->request; + + /* + * Session resumption requires the storage of data, so + * allocate it if it doesn't already exist. + */ + if (!tls_session->opaque) { + peap = tls_session->opaque = peap_alloc(tls_session, inst); + } + + /* + * Negotiate PEAP versions down. + */ + if ((handler->eap_ds->response->type.data[0] & 0x03) < tls_session->peap_flag) { + tls_session->peap_flag = handler->eap_ds->response->type.data[0] & 0x03; + } + + 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 { + RDEBUG3("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } + + /* + * Make request available to any SSL callbacks + */ + SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, request); + 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: + peap->status = PEAP_STATUS_TUNNEL_ESTABLISHED; + break; + + /* + * The TLS code is still working on the TLS + * exchange, and it's a valid TLS request. + * do nothing. + */ + case FR_TLS_HANDLED: + /* + * FIXME: If the SSL session is established, grab the state + * and EAP id from the inner tunnel, and update it with + * the expected EAP id! + */ + ret = 1; + goto done; + /* + * Handshake is done, proceed with decoding tunneled + * data. + */ + case FR_TLS_OK: + /* + * TLSv1.3 makes application data immediately avaliable + */ + if (tls_session->is_init_finished && (peap->status == PEAP_STATUS_INVALID)) peap->status = PEAP_STATUS_TUNNEL_ESTABLISHED; + break; + + /* + * Anything else: fail. + */ + default: + ret = 0; + goto done; + } + + /* + * Session is established, proceed with decoding + * tunneled data. + */ + RDEBUG2("Session established. Decoding tunneled attributes"); + + /* + * We may need PEAP data associated with the session, so + * allocate it here, if it wasn't already alloacted. + */ + if (!tls_session->opaque) { + tls_session->opaque = peap_alloc(tls_session, inst); + } + + /* + * Process the PEAP portion of the request. + */ + rcode = eappeap_process(handler, tls_session, inst->auth_type_eap); + switch (rcode) { + case RLM_MODULE_REJECT: + eaptls_fail(handler, 0); + ret = 0; + goto done; + + case RLM_MODULE_HANDLED: + eaptls_request(handler->eap_ds, tls_session); + ret = 1; + goto done; + + case RLM_MODULE_OK: + /* + * Move the saved VP's from the Access-Accept to + * our Access-Accept. + */ + peap = tls_session->opaque; + if (peap->soh_reply_vps) { + RDEBUG2("Using saved attributes from the SoH reply"); + rdebug_pair_list(L_DBG_LVL_2, request, peap->soh_reply_vps, NULL); + fr_pair_list_mcopy_by_num(handler->request->reply, + &handler->request->reply->vps, + &peap->soh_reply_vps, 0, 0, TAG_ANY); + } + if (peap->accept_vps) { + RDEBUG2("Using saved attributes from the original Access-Accept"); + rdebug_pair_list(L_DBG_LVL_2, request, peap->accept_vps, NULL); + fr_pair_list_mcopy_by_num(handler->request->reply, + &handler->request->reply->vps, + &peap->accept_vps, 0, 0, TAG_ANY); + } else if (peap->use_tunneled_reply) { + RDEBUG2("No saved attributes in the original Access-Accept"); + } + + /* + * Success: Automatically return MPPE keys. + */ + ret = eaptls_success(handler, 0); + goto done; + + /* + * 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 RLM_MODULE_UPDATED: +#ifdef WITH_PROXY + rad_assert(handler->request->proxy != NULL); +#endif + ret = 1; + goto done; + + default: + break; + } + + eaptls_fail(handler, 0); + +done: + SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, NULL); + + return ret; +} + + +/* + * The module name should be the only globally exported symbol. + * That is, everything else should be 'static'. + */ +extern rlm_eap_module_t rlm_eap_peap; +rlm_eap_module_t rlm_eap_peap = { + .name = "eap_peap", + .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 */ +}; diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/.gitignore b/src/modules/rlm_eap/types/rlm_eap_pwd/.gitignore new file mode 100644 index 0000000..01a5daa --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_pwd/.gitignore @@ -0,0 +1 @@ +all.mk diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/all.mk.in b/src/modules/rlm_eap/types/rlm_eap_pwd/all.mk.in new file mode 100644 index 0000000..e04ec27 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_pwd/all.mk.in @@ -0,0 +1,16 @@ +TARGETNAME := @targetname@ + +ifneq "$(OPENSSL_LIBS)" "" +ifneq "$(TARGETNAME)" "" +TARGET := $(TARGETNAME).a +endif +endif + +SOURCES := $(TARGETNAME).c eap_pwd.c + +SRC_CFLAGS := @mod_cflags@ +TGT_LDLIBS := @mod_ldflags@ + +SRC_INCDIRS := ../../ ../../libeap/ +TGT_PREREQS := libfreeradius-eap.a + diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/configure b/src/modules/rlm_eap/types/rlm_eap_pwd/configure new file mode 100755 index 0000000..477a210 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_pwd/configure @@ -0,0 +1,4214 @@ +#! /bin/sh +# From configure.ac Revision. +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="rlm_eap_pwd.c" +ac_subst_vars='LTLIBOBJS +LIBOBJS +targetname +mod_cflags +mod_ldflags +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +runstatedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_rlm_eap_pwd +with_openssl_lib_dir +with_openssl_include_dir +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir runstatedir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --without-rlm_eap_pwd build without rlm_eap_pwd + --with-openssl-lib-dir=DIR directory for LDAP library files + --with-openssl-include-dir=DIR directory for LDAP include files + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case <limits.h> declares $2. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + +# Check whether --with-rlm_eap_pwd was given. +if test "${with_rlm_eap_pwd+set}" = set; then : + withval=$with_rlm_eap_pwd; +fi + + + +mod_ldflags= +mod_cflags= + +if test x$with_rlm_eap_pwd != xno; then + + openssl_lib_dir= + +# Check whether --with-openssl-lib-dir was given. +if test "${with_openssl_lib_dir+set}" = set; then : + withval=$with_openssl_lib_dir; case "$withval" in + no) + as_fn_error $? "Need openssl-lib-dir" "$LINENO" 5 + ;; + yes) + ;; + *) + openssl_lib_dir="$withval" + ;; + esac + +fi + + + openssl_include_dir= + +# Check whether --with-openssl-include-dir was given. +if test "${with_openssl_include_dir+set}" = set; then : + withval=$with_openssl_include_dir; case "$withval" in + no) + as_fn_error $? "Need openssl-include-dir" "$LINENO" 5 + ;; + yes) + ;; + *) + openssl_include_dir="$withval" + ;; + esac + +fi + + + + smart_try_dir=$openssl_include_dir + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + +ac_safe=`echo "openssl/ec.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 openssl/ec.h in $try" >&5 +$as_echo_n "checking for openssl/ec.h in $try... " >&6; } + CPPFLAGS="-isystem $try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <openssl/ec.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}/openssl/ec.h" >&5 +$as_echo_n "checking for ${_prefix}/openssl/ec.h... " >&6; } + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <openssl/ec.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 openssl/ec.h" >&5 +$as_echo_n "checking for openssl/ec.h... " >&6; } + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <openssl/ec.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 try in $_smart_include_dir; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ec.h in $try" >&5 +$as_echo_n "checking for openssl/ec.h in $try... " >&6; } + CPPFLAGS="-isystem $try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <openssl/ec.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 "$ac_cv_header_openssl_ec_h" != "yes"; then + fail="$fail openssl/ec.h" + fi + + smart_try_dir=$openssl_lib_dir + + +sm_lib_safe=`echo "crypto" | sed 'y%./+-%__p_%'` +sm_func_safe=`echo "EVP_CIPHER_CTX_new" | sed 'y%./+-%__p_%'` + +old_LIBS="$LIBS" +old_CPPFLAGS="$CPPFLAGS" +smart_lib= +smart_ldflags= +smart_lib_dir= + +if test "x$smart_try_dir" != "x"; then + for try in $smart_try_dir; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EVP_CIPHER_CTX_new in -lcrypto in $try" >&5 +$as_echo_n "checking for EVP_CIPHER_CTX_new in -lcrypto in $try... " >&6; } + LIBS="-lcrypto $old_LIBS" + CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char EVP_CIPHER_CTX_new(); +int +main () +{ +EVP_CIPHER_CTX_new() + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + smart_lib="-lcrypto" + smart_ldflags="-L$try -Wl,-rpath,$try" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + break + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + LIBS="$old_LIBS" + CPPFLAGS="$old_CPPFLAGS" +fi + +if test "x$smart_lib" = "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EVP_CIPHER_CTX_new in -lcrypto" >&5 +$as_echo_n "checking for EVP_CIPHER_CTX_new in -lcrypto... " >&6; } + LIBS="-lcrypto $old_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char EVP_CIPHER_CTX_new(); +int +main () +{ +EVP_CIPHER_CTX_new() + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + smart_lib="-lcrypto" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$old_LIBS" +fi + +if test "x$smart_lib" = "x"; then + for try in /usr/local/lib /opt/lib; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EVP_CIPHER_CTX_new in -lcrypto in $try" >&5 +$as_echo_n "checking for EVP_CIPHER_CTX_new in -lcrypto in $try... " >&6; } + LIBS="-lcrypto $old_LIBS" + CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char EVP_CIPHER_CTX_new(); +int +main () +{ +EVP_CIPHER_CTX_new() + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + smart_lib="-lcrypto" + smart_ldflags="-L$try -Wl,-rpath,$try" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + break + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + LIBS="$old_LIBS" + CPPFLAGS="$old_CPPFLAGS" +fi + +if test "x$smart_lib" != "x"; then + eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes" + LIBS="$smart_ldflags $smart_lib $old_LIBS" + SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS" +fi + + if test "x$ac_cv_lib_crypto_EVP_CIPHER_CTX_new" != "xyes"; then + fail="libssl" + else + for ac_func in EVP_sha256 +do : + ac_fn_c_check_func "$LINENO" "EVP_sha256" "ac_cv_func_EVP_sha256" +if test "x$ac_cv_func_EVP_sha256" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EVP_SHA256 1 +_ACEOF + +fi +done + + if test "x$ac_cv_func_EVP_sha256" != "xyes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: EVP_sha256 not found, may have issues with WiMAX certificates" >&5 +$as_echo "$as_me: WARNING: EVP_sha256 not found, may have issues with WiMAX certificates" >&2;} + fi + + for ac_func in EC_GROUP_free +do : + ac_fn_c_check_func "$LINENO" "EC_GROUP_free" "ac_cv_func_EC_GROUP_free" +if test "x$ac_cv_func_EC_GROUP_free" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EC_GROUP_FREE 1 +_ACEOF + +fi +done + + if test "x$ac_cv_func_EC_GROUP_free" != "xyes"; then + fail="EC_GROUP_free" + fi + fi + + targetname=rlm_eap_pwd +else + targetname= + echo \*\*\* module rlm_eap_pwd is disabled. +fi + +if test x"$fail" != x""; then + if test x"${enable_strict_dependencies}" = x"yes"; then + as_fn_error $? "set --without-rlm_eap_pwd to disable it explicitly." "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_eap_pwd." >&5 +$as_echo "$as_me: WARNING: silently not building rlm_eap_pwd." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_eap_pwd requires: $fail." >&5 +$as_echo "$as_me: WARNING: FAILURE: rlm_eap_pwd requires: $fail." >&2;} + targetname="" + fi +fi + + + + +ac_config_files="$ac_config_files all.mk" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/configure.ac b/src/modules/rlm_eap/types/rlm_eap_pwd/configure.ac new file mode 100644 index 0000000..64e5919 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_pwd/configure.ac @@ -0,0 +1,91 @@ +AC_PREREQ([2.68]) +AC_INIT(rlm_eap_pwd.c) +AC_REVISION($Revision$) +FR_INIT_MODULE([rlm_eap_pwd]) + +mod_ldflags= +mod_cflags= + +if test x$with_[]modname != xno; then + + dnl ############################################################ + dnl # Check for command line options + dnl ############################################################ + dnl extra argument: --with-openssl-lib-dir + openssl_lib_dir= + AC_ARG_WITH(openssl-lib-dir, + [ --with-openssl-lib-dir=DIR directory for LDAP library files []], + [ case "$withval" in + no) + AC_MSG_ERROR(Need openssl-lib-dir) + ;; + yes) + ;; + *) + openssl_lib_dir="$withval" + ;; + esac ] + ) + + dnl extra argument: --with-openssl-include-dir + openssl_include_dir= + AC_ARG_WITH(openssl-include-dir, + [ --with-openssl-include-dir=DIR directory for LDAP include files []], + [ case "$withval" in + no) + AC_MSG_ERROR(Need openssl-include-dir) + ;; + yes) + ;; + *) + openssl_include_dir="$withval" + ;; + esac ] + ) + + dnl ############################################################ + dnl # Check for header files + dnl ############################################################ + + smart_try_dir=$openssl_include_dir + FR_SMART_CHECK_INCLUDE(openssl/ec.h) + if test "$ac_cv_header_openssl_ec_h" != "yes"; then + fail="$fail openssl/ec.h" + fi + + smart_try_dir=$openssl_lib_dir + FR_SMART_CHECK_LIB(crypto, EVP_CIPHER_CTX_new) + if test "x$ac_cv_lib_crypto_EVP_CIPHER_CTX_new" != "xyes"; then + fail="libssl" + else + AC_CHECK_FUNCS(EVP_sha256) + if test "x$ac_cv_func_EVP_sha256" != "xyes"; then + AC_MSG_WARN([EVP_sha256 not found, may have issues with WiMAX certificates]) + fi + + AC_CHECK_FUNCS(EC_GROUP_free) + if test "x$ac_cv_func_EC_GROUP_free" != "xyes"; then + fail="EC_GROUP_free" + fi + fi + + targetname=modname +else + targetname= + echo \*\*\* module modname is disabled. +fi + +if test x"$fail" != x""; then + if test x"${enable_strict_dependencies}" = x"yes"; then + AC_MSG_ERROR([set --without-]modname[ to disable it explicitly.]) + else + AC_MSG_WARN([silently not building ]modname[.]) + AC_MSG_WARN([FAILURE: ]modname[ requires: $fail.]) + targetname="" + fi +fi + +AC_SUBST(mod_ldflags) +AC_SUBST(mod_cflags) +AC_SUBST(targetname) +AC_OUTPUT(all.mk) diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/const_time.h b/src/modules/rlm_eap/types/rlm_eap_pwd/const_time.h new file mode 100644 index 0000000..b717dd5 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_pwd/const_time.h @@ -0,0 +1,190 @@ +/* + * Helper functions for constant time operations + * Copyright (c) 2019, The Linux Foundation + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + * + * These helper functions can be used to implement logic that needs to minimize + * externally visible differences in execution path by avoiding use of branches, + * avoiding early termination or other time differences, and forcing same memory + * access pattern regardless of values. + */ + +#ifndef CONST_TIME_H +#define CONST_TIME_H + + +#if defined(__clang__) +#define NO_UBSAN_UINT_OVERFLOW \ + __attribute__((no_sanitize("unsigned-integer-overflow"))) +#else +#define NO_UBSAN_UINT_OVERFLOW +#endif + +/** + * const_time_fill_msb - Fill all bits with MSB value + * @param val Input value + * @return Value with all the bits set to the MSB of the input val + */ +static inline unsigned int const_time_fill_msb(unsigned int val) +{ + /* Move the MSB to LSB and multiple by -1 to fill in all bits. */ + return (val >> (sizeof(val) * 8 - 1)) * ~0U; +} + + +/* @return -1 if val is zero; 0 if val is not zero */ +static inline unsigned int const_time_is_zero(unsigned int val) + NO_UBSAN_UINT_OVERFLOW +{ + /* Set MSB to 1 for 0 and fill rest of bits with the MSB value */ + return const_time_fill_msb(~val & (val - 1)); +} + + +/* @return -1 if a == b; 0 if a != b */ +static inline unsigned int const_time_eq(unsigned int a, unsigned int b) +{ + return const_time_is_zero(a ^ b); +} + + +/* @return -1 if a == b; 0 if a != b */ +static inline unsigned char const_time_eq_u8(unsigned int a, unsigned int b) +{ + return (unsigned char) const_time_eq(a, b); +} + + +/** + * const_time_eq_bin - Constant time memory comparison + * @param a First buffer to compare + * @param b Second buffer to compare + * @param len Number of octets to compare + * @return -1 if buffers are equal, 0 if not + * + * This function is meant for comparing passwords or hash values where + * difference in execution time or memory access pattern could provide external + * observer information about the location of the difference in the memory + * buffers. The return value does not behave like memcmp(), i.e., + * const_time_eq_bin() cannot be used to sort items into a defined order. Unlike + * memcmp(), the execution time of const_time_eq_bin() does not depend on the + * contents of the compared memory buffers, but only on the total compared + * length. + */ +static inline unsigned int const_time_eq_bin(const void *a, const void *b, + size_t len) +{ + const unsigned char *aa = a; + const unsigned char *bb = b; + size_t i; + unsigned char res = 0; + + for (i = 0; i < len; i++) + res |= aa[i] ^ bb[i]; + + return const_time_is_zero(res); +} + + +/** + * const_time_select - Constant time unsigned int selection + * @param mask 0 (false) or -1 (true) to identify which value to select + * @param true_val Value to select for the true case + * @param false_val Value to select for the false case + * @return true_val if mask == -1, false_val if mask == 0 + */ +static inline unsigned int const_time_select(unsigned int mask, + unsigned int true_val, + unsigned int false_val) +{ + return (mask & true_val) | (~mask & false_val); +} + + +/** + * const_time_select_int - Constant time int selection + * @param mask 0 (false) or -1 (true) to identify which value to select + * @param true_val Value to select for the true case + * @param false_val Value to select for the false case + * @return true_val if mask == -1, false_val if mask == 0 + */ +static inline int const_time_select_int(unsigned int mask, int true_val, + int false_val) +{ + return (int) const_time_select(mask, (unsigned int) true_val, + (unsigned int) false_val); +} + + +/** + * const_time_select_u8 - Constant time u8 selection + * @param mask 0 (false) or -1 (true) to identify which value to select + * @param true_val Value to select for the true case + * @param false_val Value to select for the false case + * @return true_val if mask == -1, false_val if mask == 0 + */ +static inline unsigned char const_time_select_u8(unsigned char mask, unsigned char true_val, unsigned char false_val) +{ + return (unsigned char) const_time_select(mask, true_val, false_val); +} + + +/** + * const_time_select_s8 - Constant time s8 selection + * @param mask 0 (false) or -1 (true) to identify which value to select + * @param true_val Value to select for the true case + * @param false_val Value to select for the false case + * @return true_val if mask == -1, false_val if mask == 0 + */ +static inline char const_time_select_s8(char mask, char true_val, char false_val) +{ + return (char) const_time_select(mask, (unsigned int) true_val, + (unsigned int) false_val); +} + + +/** + * const_time_select_bin - Constant time binary buffer selection copy + * @param mask 0 (false) or -1 (true) to identify which value to copy + * @param true_val Buffer to copy for the true case + * @param false_val Buffer to copy for the false case + * @param len Number of octets to copy + * @param dst Destination buffer for the copy + * + * This function copies the specified buffer into the destination buffer using + * operations with identical memory access pattern regardless of which buffer + * is being copied. + */ +static inline void const_time_select_bin(unsigned char mask, const unsigned char *true_val, + const unsigned char *false_val, size_t len, + unsigned char *dst) +{ + size_t i; + + for (i = 0; i < len; i++) + dst[i] = const_time_select_u8(mask, true_val[i], false_val[i]); +} + + +static inline int const_time_memcmp(const void *a, const void *b, size_t len) +{ + const unsigned char *aa = a; + const unsigned char *bb = b; + int diff, res = 0; + unsigned int mask; + + if (len == 0) + return 0; + do { + len--; + diff = (int) aa[len] - (int) bb[len]; + mask = const_time_is_zero((unsigned int) diff); + res = const_time_select_int(mask, res, diff); + } while (len); + + return res; +} + +#endif /* CONST_TIME_H */ diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c b/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c new file mode 100644 index 0000000..2626052 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c @@ -0,0 +1,933 @@ +/** + * copyright holder grants permission for redistribution and use in source + * and binary forms, with or without modification, provided that the + * following conditions are met: + * 1. Redistribution of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer + * in all source files. + * 2. Redistribution in binary form must retain the above copyright + * notice, this list of conditions, and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * "DISCLAIMER OF LIABILITY + * + * THIS SOFTWARE IS PROVIDED BY DAN HARKINS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INDUSTRIAL LOUNGE BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE." + * + * This license and distribution terms cannot be changed. In other words, + * this code cannot simply be copied and put under a different distribution + * license (including the GNU public license). + * + * @copyright (c) Dan Harkins, 2012 + */ + +RCSID("$Id$") +USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ + +#include "eap_pwd.h" +#include "const_time.h" +#include <freeradius-devel/openssl3.h> + +static uint8_t allzero[SHA256_DIGEST_LENGTH] = { 0x00 }; + +/* The random function H(x) = HMAC-SHA256(0^32, x) */ +static void pwd_hmac_final(HMAC_CTX *hmac_ctx, uint8_t *digest) +{ + unsigned int mdlen = SHA256_DIGEST_LENGTH; + HMAC_Final(hmac_ctx, digest, &mdlen); +// HMAC_CTX_reset(hmac_ctx); +} + +/* a counter-based KDF based on NIST SP800-108 */ +static void eap_pwd_kdf(uint8_t *key, int keylen, char const *label, + int label_len, uint8_t *result, int result_bit_len) +{ + HMAC_CTX *hmac_ctx; + uint8_t digest[SHA256_DIGEST_LENGTH]; + uint16_t i, ctr, L; + int result_byte_len, len = 0; + unsigned int mdlen = SHA256_DIGEST_LENGTH; + uint8_t mask = 0xff; + + MEM(hmac_ctx = HMAC_CTX_new()); + result_byte_len = (result_bit_len + 7) / 8; + + ctr = 0; + L = htons(result_bit_len); + while (len < result_byte_len) { + ctr++; i = htons(ctr); + + HMAC_Init_ex(hmac_ctx, key, keylen, EVP_sha256(), NULL); + if (ctr > 1) HMAC_Update(hmac_ctx, digest, mdlen); + HMAC_Update(hmac_ctx, (uint8_t *) &i, sizeof(uint16_t)); + HMAC_Update(hmac_ctx, (uint8_t const *)label, label_len); + HMAC_Update(hmac_ctx, (uint8_t *) &L, sizeof(uint16_t)); + HMAC_Final(hmac_ctx, digest, &mdlen); + if ((len + (int) mdlen) > result_byte_len) { + memcpy(result + len, digest, result_byte_len - len); + } else { + memcpy(result + len, digest, mdlen); + } + len += mdlen; +// HMAC_CTX_reset(hmac_ctx); + } + + /* since we're expanding to a bit length, mask off the excess */ + if (result_bit_len % 8) { + mask <<= (8 - (result_bit_len % 8)); + result[result_byte_len - 1] &= mask; + } + + HMAC_CTX_free(hmac_ctx); +} + +static BIGNUM *consttime_BN (void) +{ + BIGNUM *bn; + + bn = BN_new(); + if (bn) BN_set_flags(bn, BN_FLG_CONSTTIME); + return bn; +} + +/* + * compute the legendre symbol in constant time + */ +static int legendre(BIGNUM *a, BIGNUM *p, BN_CTX *bnctx) +{ + int symbol; + unsigned int mask; + BIGNUM *res, *pm1over2; + + pm1over2 = consttime_BN(); + res = consttime_BN(); + + if (!BN_sub(pm1over2, p, BN_value_one()) || + !BN_rshift1(pm1over2, pm1over2) || + !BN_mod_exp_mont_consttime(res, a, pm1over2, p, bnctx, NULL)) { + BN_free(pm1over2); + BN_free(res); + return -2; + } + + symbol = -1; + mask = const_time_eq(BN_is_word(res, 1), 1); + symbol = const_time_select_int(mask, 1, symbol); + mask = const_time_eq(BN_is_zero(res), 1); + symbol = const_time_select_int(mask, -1, symbol); + + BN_free(pm1over2); + BN_free(res); + + return symbol; +} + +static void do_equation(EC_GROUP *group, BIGNUM *y2, BIGNUM *x, BN_CTX *bnctx) +{ + BIGNUM *p, *a, *b, *tmp1, *pm1; + + tmp1 = BN_new(); + pm1 = BN_new(); + p = BN_new(); + a = BN_new(); + b = BN_new(); + EC_GROUP_get_curve(group, p, a, b, bnctx); + + BN_sub(pm1, p, BN_value_one()); + + /* + * y2 = x^3 + ax + b + */ + BN_mod_sqr(tmp1, x, p, bnctx); + BN_mod_mul(y2, tmp1, x, p, bnctx); + BN_mod_mul(tmp1, a, x, p, bnctx); + BN_mod_add_quick(y2, y2, tmp1, p); + BN_mod_add_quick(y2, y2, b, p); + + BN_free(tmp1); + BN_free(pm1); + BN_free(p); + BN_free(a); + BN_free(b); + + return; +} + +static int is_quadratic_residue(BIGNUM *val, BIGNUM *p, BIGNUM *qr, BIGNUM *qnr, BN_CTX *bnctx) +{ + int offset, check, ret = 0; + BIGNUM *r = NULL, *pm1 = NULL, *res = NULL, *qr_or_qnr = NULL; + unsigned int mask; + unsigned char *qr_bin = NULL, *qnr_bin = NULL, *qr_or_qnr_bin = NULL; + + if (((r = consttime_BN()) == NULL) || + ((res = consttime_BN()) == NULL) || + ((qr_or_qnr = consttime_BN()) == NULL) || + ((pm1 = consttime_BN()) == NULL)) { + ret = -2; + goto fail; + } + + if (((qr_bin = (unsigned char *)malloc(BN_num_bytes(p))) == NULL) || + ((qnr_bin = (unsigned char *)malloc(BN_num_bytes(p))) == NULL) || + ((qr_or_qnr_bin = (unsigned char *)malloc(BN_num_bytes(p))) == NULL)) { + ret = -2; + goto fail; + } + + /* + * we select binary in constant time so make them binary + */ + memset(qr_bin, 0, BN_num_bytes(p)); + memset(qnr_bin, 0, BN_num_bytes(p)); + memset(qr_or_qnr_bin, 0, BN_num_bytes(p)); + + offset = BN_num_bytes(p) - BN_num_bytes(qr); + BN_bn2bin(qr, qr_bin + offset); + + offset = BN_num_bytes(p) - BN_num_bytes(qnr); + BN_bn2bin(qnr, qnr_bin + offset); + + /* + * r = (random() mod p-1) + 1 + */ + BN_sub(pm1, p, BN_value_one()); + BN_rand_range(r, pm1); + BN_add(r, r, BN_value_one()); + + BN_copy(res, val); + + /* + * res = val * r * r which ensures res != val but has same quadratic residocity + */ + BN_mod_mul(res, res, r, p, bnctx); + BN_mod_mul(res, res, r, p, bnctx); + + /* + * if r is even (mask is -1) then multiply by qnr and our check is qnr + * otherwise multiply by qr and our check is qr + */ + mask = const_time_is_zero(BN_is_odd(r)); + const_time_select_bin(mask, qnr_bin, qr_bin, BN_num_bytes(p), qr_or_qnr_bin); + BN_bin2bn(qr_or_qnr_bin, BN_num_bytes(p), qr_or_qnr); + BN_mod_mul(res, res, qr_or_qnr, p, bnctx); + check = const_time_select_int(mask, -1, 1); + + if ((ret = legendre(res, p, bnctx)) == -2) { + ret = -1; /* just say no it's not */ + goto fail; + } + mask = const_time_eq(ret, check); + ret = const_time_select_int(mask, 1, 0); + +fail: + if (qr_bin != NULL) free(qr_bin); + if (qnr_bin != NULL) free(qnr_bin); + if (qr_or_qnr_bin != NULL) free(qr_or_qnr_bin); + BN_free(r); + BN_free(res); + BN_free(qr_or_qnr); + BN_free(pm1); + + return ret; +} + +int compute_password_element (REQUEST *request, pwd_session_t *session, uint16_t grp_num, + char const *password, int password_len, + char const *id_server, int id_server_len, + char const *id_peer, int id_peer_len, + uint32_t *token) +{ + BIGNUM *x_candidate = NULL, *rnd = NULL, *y_sqrd = NULL, *qr = NULL, *qnr = NULL, *y1 = NULL, *y2 = NULL, *y = NULL, *exp = NULL; + EVP_MD_CTX *hmac_ctx; + EVP_PKEY *hmac_pkey; + uint8_t pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, *xbuf = NULL, *pm1buf = NULL, *y1buf = NULL, *y2buf = NULL, *ybuf = NULL, ctr; + int nid, is_odd, primebitlen, primebytelen, ret = 0, found = 0, mask; + int save, i, rbits, qr_or_qnr, save_is_odd = 0, cmp; + unsigned int skip; + + MEM(hmac_ctx = EVP_MD_CTX_new()); + MEM(hmac_pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, allzero, sizeof(allzero))); + + switch (grp_num) { /* from IANA registry for IKE D-H groups */ + case 19: + nid = NID_X9_62_prime256v1; + break; + + case 20: + nid = NID_secp384r1; + break; + + case 21: + nid = NID_secp521r1; + break; + + case 25: + nid = NID_X9_62_prime192v1; + break; + + case 26: + nid = NID_secp224r1; + break; + + default: + DEBUG("unknown group %d", grp_num); + goto fail; + } + + session->pwe = NULL; + session->order = NULL; + session->prime = NULL; + + if ((session->group = EC_GROUP_new_by_curve_name(nid)) == NULL) { + DEBUG("unable to create EC_GROUP"); + goto fail; + } + + if (((rnd = consttime_BN()) == NULL) || + ((session->pwe = EC_POINT_new(session->group)) == NULL) || + ((session->order = consttime_BN()) == NULL) || + ((session->prime = consttime_BN()) == NULL) || + ((qr = consttime_BN()) == NULL) || + ((qnr = consttime_BN()) == NULL) || + ((x_candidate = consttime_BN()) == NULL) || + ((y_sqrd = consttime_BN()) == NULL) || + ((y1 = consttime_BN()) == NULL) || + ((y2 = consttime_BN()) == NULL) || + ((y = consttime_BN()) == NULL) || + ((exp = consttime_BN()) == NULL)) { + DEBUG("unable to create bignums"); + goto fail; + } + + if (!EC_GROUP_get_curve(session->group, session->prime, NULL, NULL, NULL)) { + DEBUG("unable to get prime for GFp curve"); + goto fail; + } + + if (!EC_GROUP_get_order(session->group, session->order, NULL)) { + DEBUG("unable to get order for curve"); + goto fail; + } + + primebitlen = BN_num_bits(session->prime); + primebytelen = BN_num_bytes(session->prime); + if ((prfbuf = talloc_zero_array(session, uint8_t, primebytelen)) == NULL) { + DEBUG("unable to alloc space for prf buffer"); + goto fail; + } + if ((xbuf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) { + DEBUG("unable to alloc space for x buffer"); + goto fail; + } + if ((pm1buf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) { + DEBUG("unable to alloc space for pm1 buffer"); + goto fail; + } + if ((y1buf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) { + DEBUG("unable to alloc space for y1 buffer"); + goto fail; + } + if ((y2buf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) { + DEBUG("unable to alloc space for y2 buffer"); + goto fail; + } + if ((ybuf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) { + DEBUG("unable to alloc space for y buffer"); + goto fail; + } + + + /* + * derive random quadradic residue and quadratic non-residue + */ + do { + BN_rand_range(qr, session->prime); + } while (legendre(qr, session->prime, session->bnctx) != 1); + + do { + BN_rand_range(qnr, session->prime); + } while (legendre(qnr, session->prime, session->bnctx) != -1); + + if (!BN_sub(rnd, session->prime, BN_value_one())) { + goto fail; + } + BN_bn2bin(rnd, pm1buf); + + save_is_odd = 0; + found = 0; + memset(xbuf, 0, primebytelen); + ctr = 0; + while (ctr < 40) { + ctr++; + + /* + * compute counter-mode password value and stretch to prime + * pwd-seed = H(token | peer-id | server-id | password | + * counter) + */ + EVP_DigestSignInit(hmac_ctx, NULL, EVP_sha256(), NULL, hmac_pkey); + EVP_DigestSignUpdate(hmac_ctx, (uint8_t *)token, sizeof(*token)); + EVP_DigestSignUpdate(hmac_ctx, (uint8_t const *)id_peer, id_peer_len); + EVP_DigestSignUpdate(hmac_ctx, (uint8_t const *)id_server, id_server_len); + EVP_DigestSignUpdate(hmac_ctx, (uint8_t const *)password, password_len); + EVP_DigestSignUpdate(hmac_ctx, (uint8_t *)&ctr, sizeof(ctr)); + + { + size_t mdlen = SHA256_DIGEST_LENGTH; + + EVP_DigestSignFinal(hmac_ctx, pwe_digest, &mdlen); + EVP_MD_CTX_reset(hmac_ctx); + } + + BN_bin2bn(pwe_digest, SHA256_DIGEST_LENGTH, rnd); + eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH, "EAP-pwd Hunting And Pecking", + strlen("EAP-pwd Hunting And Pecking"), prfbuf, primebitlen); + + /* + * eap_pwd_kdf() returns a string of bits 0..primebitlen but + * BN_bin2bn will treat that string of bits as a big endian + * number. If the primebitlen is not an even multiple of 8 + * then excessive bits-- those _after_ primebitlen-- so now + * we have to shift right the amount we masked off. + */ + if (primebitlen % 8) { + rbits = 8 - (primebitlen % 8); + for (i = primebytelen - 1; i > 0; i--) { + prfbuf[i] = (prfbuf[i - 1] << (8 - rbits)) | (prfbuf[i] >> rbits); + } + prfbuf[0] >>= rbits; + } + BN_bin2bn(prfbuf, primebytelen, x_candidate); + + /* + * it would've been better if the spec reduced the candidate + * modulo the prime but it didn't. So if the candidate >= prime + * we need to skip it but still run through the operations below + */ + cmp = const_time_memcmp(pm1buf, prfbuf, primebytelen); + skip = const_time_fill_msb((unsigned int)cmp); + + /* + * need to unambiguously identify the solution, if there is + * one.. + */ + is_odd = BN_is_odd(rnd); + + /* + * check whether x^3 + a*x + b is a quadratic residue + * + * save the first quadratic residue we find in the loop but do + * it in constant time. + */ + do_equation(session->group, y_sqrd, x_candidate, session->bnctx); + qr_or_qnr = is_quadratic_residue(y_sqrd, session->prime, qr, qnr, session->bnctx); + + /* + * if the candidate >= prime then we want to skip it + */ + qr_or_qnr = const_time_select(skip, 0, qr_or_qnr); + + /* + * if we haven't found PWE yet (found = 0) then mask will be true, + * if we have found PWE then mask will be false + */ + mask = const_time_select(found, 0, -1); + + /* + * save will be 1 if we want to save this value-- i.e. we haven't + * found PWE yet and this is a quadratic residue-- and 0 otherwise + */ + save = const_time_select(mask, qr_or_qnr, 0); + + /* + * mask will be true (-1) if we want to save this and false (0) + * otherwise + */ + mask = const_time_eq(save, 1); + + const_time_select_bin(mask, prfbuf, xbuf, primebytelen, xbuf); + save_is_odd = const_time_select(mask, is_odd, save_is_odd); + found = const_time_select(mask, -1, found); + } + + /* + * now we can savely construct PWE + */ + BN_bin2bn(xbuf, primebytelen, x_candidate); + do_equation(session->group, y_sqrd, x_candidate, session->bnctx); + if ( !BN_add(exp, session->prime, BN_value_one()) || + !BN_rshift(exp, exp, 2) || + !BN_mod_exp_mont_consttime(y1, y_sqrd, exp, session->prime, session->bnctx, NULL) || + !BN_sub(y2, session->prime, y1) || + !BN_bn2bin(y1, y1buf) || + !BN_bn2bin(y2, y2buf)) { + DEBUG("unable to compute y"); + goto fail; + } + mask = const_time_eq(save_is_odd, BN_is_odd(y1)); + const_time_select_bin(mask, y1buf, y2buf, primebytelen, ybuf); + if (BN_bin2bn(ybuf, primebytelen, y) == NULL || + !EC_POINT_set_affine_coordinates(session->group, session->pwe, x_candidate, y, session->bnctx)) { + DEBUG("unable to set point coordinate"); + goto fail; + } + + session->group_num = grp_num; + if (0) { + fail: /* DON'T free session, it's in handler->opaque */ + ret = -1; + } + + /* cleanliness and order.... */ + BN_clear_free(x_candidate); + BN_clear_free(y_sqrd); + BN_clear_free(qr); + BN_clear_free(qnr); + BN_clear_free(rnd); + BN_clear_free(y1); + BN_clear_free(y2); + BN_clear_free(y); + BN_clear_free(exp); + + if (prfbuf) talloc_free(prfbuf); + if (xbuf) talloc_free(xbuf); + if (pm1buf) talloc_free(pm1buf); + if (y1buf) talloc_free(y1buf); + if (y2buf) talloc_free(y2buf); + if (ybuf) talloc_free(ybuf); + + EVP_MD_CTX_free(hmac_ctx); + EVP_PKEY_free(hmac_pkey); + + return ret; +} + +int compute_scalar_element(REQUEST *request, pwd_session_t *session, BN_CTX *bn_ctx) +{ + BIGNUM *mask = NULL; + int ret = -1; + + MEM(session->private_value = BN_new()); + MEM(session->my_element = EC_POINT_new(session->group)); + MEM(session->my_scalar = BN_new()); + + MEM(mask = BN_new()); + + if (BN_rand_range(session->private_value, session->order) != 1) { + REDEBUG("Unable to get randomness for private_value"); + goto error; + } + if (BN_rand_range(mask, session->order) != 1) { + REDEBUG("Unable to get randomness for mask"); + goto error; + } + BN_add(session->my_scalar, session->private_value, mask); + BN_mod(session->my_scalar, session->my_scalar, session->order, bn_ctx); + + if (!EC_POINT_mul(session->group, session->my_element, NULL, session->pwe, mask, bn_ctx)) { + REDEBUG("Server element allocation failed"); + goto error; + } + + if (!EC_POINT_invert(session->group, session->my_element, bn_ctx)) { + REDEBUG("Server element inversion failed"); + goto error; + } + + ret = 0; + +error: + BN_clear_free(mask); + + return ret; +} + +int process_peer_commit(REQUEST *request, pwd_session_t *session, uint8_t *in, size_t in_len, BN_CTX *bn_ctx) +{ + uint8_t *ptr; + size_t data_len; + BIGNUM *x = NULL, *y = NULL, *cofactor = NULL; + EC_POINT *K = NULL, *point = NULL; + int ret = 1; + + MEM(session->peer_scalar = BN_new()); + MEM(session->k = BN_new()); + MEM(session->peer_element = EC_POINT_new(session->group)); + MEM(point = EC_POINT_new(session->group)); + MEM(K = EC_POINT_new(session->group)); + + MEM(cofactor = BN_new()); + MEM(x = BN_new()); + MEM(y = BN_new()); + + if (!EC_GROUP_get_cofactor(session->group, cofactor, NULL)) { + REDEBUG("Unable to get group co-factor"); + goto finish; + } + + /* element, x then y, followed by scalar */ + ptr = (uint8_t *)in; + data_len = BN_num_bytes(session->prime); + + /* + * Did the peer send enough data? + */ + if (in_len < (2 * data_len + BN_num_bytes(session->order))) { + REDEBUG("Invalid commit packet"); + goto finish; + } + + BN_bin2bn(ptr, data_len, x); + ptr += data_len; + BN_bin2bn(ptr, data_len, y); + ptr += data_len; + + data_len = BN_num_bytes(session->order); + BN_bin2bn(ptr, data_len, session->peer_scalar); + + /* validate received scalar */ + if (BN_is_zero(session->peer_scalar) || + BN_is_one(session->peer_scalar) || + BN_cmp(session->peer_scalar, session->order) >= 0) { + REDEBUG("Peer's scalar is not within the allowed range"); + goto finish; + } + + if (!EC_POINT_set_affine_coordinates(session->group, session->peer_element, x, y, bn_ctx)) { + REDEBUG("Unable to get coordinates of peer's element"); + goto finish; + } + + /* validate received element */ + if (!EC_POINT_is_on_curve(session->group, session->peer_element, bn_ctx) || + EC_POINT_is_at_infinity(session->group, session->peer_element)) { + REDEBUG("Peer's element is not a point on the elliptic curve"); + goto finish; + } + + /* check to ensure peer's element is not in a small sub-group */ + if (BN_cmp(cofactor, BN_value_one())) { + if (!EC_POINT_mul(session->group, point, NULL, session->peer_element, cofactor, NULL)) { + REDEBUG("Unable to multiply element by co-factor"); + goto finish; + } + + if (EC_POINT_is_at_infinity(session->group, point)) { + REDEBUG("Peer's element is in small sub-group"); + goto finish; + } + } + + /* detect reflection attacks */ + if (BN_cmp(session->peer_scalar, session->my_scalar) == 0 || + EC_POINT_cmp(session->group, session->peer_element, session->my_element, bn_ctx) == 0) { + REDEBUG("Reflection attack detected"); + goto finish; + } + + /* compute the shared key, k */ + if ((!EC_POINT_mul(session->group, K, NULL, session->pwe, session->peer_scalar, bn_ctx)) || + (!EC_POINT_add(session->group, K, K, session->peer_element, bn_ctx)) || + (!EC_POINT_mul(session->group, K, NULL, K, session->private_value, bn_ctx))) { + REDEBUG("Unable to compute shared key, k"); + goto finish; + } + + /* ensure that the shared key isn't in a small sub-group */ + if (BN_cmp(cofactor, BN_value_one())) { + if (!EC_POINT_mul(session->group, K, NULL, K, cofactor, NULL)) { + REDEBUG("Unable to multiply k by co-factor"); + goto finish; + } + } + + /* + * This check is strictly speaking just for the case above where + * co-factor > 1 but it was suggested that even though this is probably + * never going to happen it is a simple and safe check "just to be + * sure" so let's be safe. + */ + if (EC_POINT_is_at_infinity(session->group, K)) { + REDEBUG("K is point-at-infinity"); + goto finish; + } + + if (!EC_POINT_get_affine_coordinates(session->group, K, session->k, NULL, bn_ctx)) { + REDEBUG("Unable to get shared secret from K"); + goto finish; + } + ret = 0; + +finish: + EC_POINT_clear_free(K); + EC_POINT_clear_free(point); + BN_clear_free(cofactor); + BN_clear_free(x); + BN_clear_free(y); + + return ret; +} + +int compute_server_confirm(REQUEST *request, pwd_session_t *session, uint8_t *out, BN_CTX *bn_ctx) +{ + BIGNUM *x = NULL, *y = NULL; + HMAC_CTX *hmac_ctx = NULL; + uint8_t *cruft = NULL; + int offset, req = -1; + + /* + * Each component of the cruft will be at most as big as the prime + */ + MEM(cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->prime))); + MEM(x = BN_new()); + MEM(y = BN_new()); + + /* + * commit is H(k | server_element | server_scalar | peer_element | + * peer_scalar | ciphersuite) + */ + MEM(hmac_ctx = HMAC_CTX_new()); + HMAC_Init_ex(hmac_ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL); + + /* + * Zero the memory each time because this is mod prime math and some + * value may start with a few zeros and the previous one did not. + * + * First is k + */ + offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k); + BN_bn2bin(session->k, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); + + /* + * next is server element: x, y + */ + if (!EC_POINT_get_affine_coordinates(session->group, session->my_element, x, y, bn_ctx)) { + REDEBUG("Unable to get coordinates of server element"); + goto finish; + } + memset(cruft, 0, BN_num_bytes(session->prime)); + offset = BN_num_bytes(session->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); + + memset(cruft, 0, BN_num_bytes(session->prime)); + offset = BN_num_bytes(session->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); + + /* + * and server scalar + */ + memset(cruft, 0, BN_num_bytes(session->prime)); + offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar); + BN_bn2bin(session->my_scalar, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order)); + + /* + * next is peer element: x, y + */ + if (!EC_POINT_get_affine_coordinates(session->group, session->peer_element, x, y, bn_ctx)) { + REDEBUG("Unable to get coordinates of peer's element"); + goto finish; + } + + memset(cruft, 0, BN_num_bytes(session->prime)); + offset = BN_num_bytes(session->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); + + memset(cruft, 0, BN_num_bytes(session->prime)); + offset = BN_num_bytes(session->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); + + /* + * and peer scalar + */ + memset(cruft, 0, BN_num_bytes(session->prime)); + offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar); + BN_bn2bin(session->peer_scalar, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order)); + + /* + * finally, ciphersuite + */ + HMAC_Update(hmac_ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite)); + + pwd_hmac_final(hmac_ctx, out); + + req = 0; + +finish: + HMAC_CTX_free(hmac_ctx); + talloc_free(cruft); + BN_free(x); + BN_free(y); + + return req; +} + +int compute_peer_confirm(REQUEST *request, pwd_session_t *session, uint8_t *out, BN_CTX *bn_ctx) +{ + BIGNUM *x = NULL, *y = NULL; + HMAC_CTX *hmac_ctx = NULL; + uint8_t *cruft = NULL; + int offset, req = -1; + + /* + * Each component of the cruft will be at most as big as the prime + */ + MEM(cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->prime))); + MEM(x = BN_new()); + MEM(y = BN_new()); + + /* + * commit is H(k | server_element | server_scalar | peer_element | + * peer_scalar | ciphersuite) + */ + MEM(hmac_ctx = HMAC_CTX_new()); + HMAC_Init_ex(hmac_ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL); + + /* + * Zero the memory each time because this is mod prime math and some + * value may start with a few zeros and the previous one did not. + * + * First is k + */ + offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k); + BN_bn2bin(session->k, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); + + /* + * then peer element: x, y + */ + if (!EC_POINT_get_affine_coordinates(session->group, session->peer_element, x, y, bn_ctx)) { + REDEBUG("Unable to get coordinates of peer's element"); + goto finish; + } + + memset(cruft, 0, BN_num_bytes(session->prime)); + offset = BN_num_bytes(session->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); + + memset(cruft, 0, BN_num_bytes(session->prime)); + offset = BN_num_bytes(session->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); + + /* + * and peer scalar + */ + memset(cruft, 0, BN_num_bytes(session->prime)); + offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar); + BN_bn2bin(session->peer_scalar, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order)); + + /* + * then server element: x, y + */ + if (!EC_POINT_get_affine_coordinates(session->group, session->my_element, x, y, bn_ctx)) { + REDEBUG("Unable to get coordinates of server element"); + goto finish; + } + memset(cruft, 0, BN_num_bytes(session->prime)); + offset = BN_num_bytes(session->prime) - BN_num_bytes(x); + BN_bn2bin(x, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); + + memset(cruft, 0, BN_num_bytes(session->prime)); + offset = BN_num_bytes(session->prime) - BN_num_bytes(y); + BN_bn2bin(y, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); + + /* + * and server scalar + */ + memset(cruft, 0, BN_num_bytes(session->prime)); + offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar); + BN_bn2bin(session->my_scalar, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order)); + + /* + * finally, ciphersuite + */ + HMAC_Update(hmac_ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite)); + + pwd_hmac_final(hmac_ctx, out); + + req = 0; +finish: + HMAC_CTX_free(hmac_ctx); + talloc_free(cruft); + BN_free(x); + BN_free(y); + + return req; +} + +int compute_keys(UNUSED REQUEST *request, pwd_session_t *session, uint8_t *peer_confirm, uint8_t *msk, uint8_t *emsk) +{ + HMAC_CTX *hmac_ctx; + uint8_t mk[SHA256_DIGEST_LENGTH], *cruft; + uint8_t session_id[SHA256_DIGEST_LENGTH + 1]; + uint8_t msk_emsk[128]; /* 64 each */ + int offset; + + MEM(cruft = talloc_array(session, uint8_t, BN_num_bytes(session->prime))); + MEM(hmac_ctx = HMAC_CTX_new()); + + /* + * first compute the session-id = TypeCode | H(ciphersuite | scal_p | + * scal_s) + */ + session_id[0] = PW_EAP_PWD; + HMAC_Init_ex(hmac_ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL); + HMAC_Update(hmac_ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite)); + offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar); + memset(cruft, 0, BN_num_bytes(session->prime)); + BN_bn2bin(session->peer_scalar, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order)); + offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar); + memset(cruft, 0, BN_num_bytes(session->prime)); + BN_bn2bin(session->my_scalar, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order)); + pwd_hmac_final(hmac_ctx, (uint8_t *)&session_id[1]); + + /* then compute MK = H(k | commit-peer | commit-server) */ + HMAC_Init_ex(hmac_ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL); + + memset(cruft, 0, BN_num_bytes(session->prime)); + offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k); + BN_bn2bin(session->k, cruft + offset); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); + + HMAC_Update(hmac_ctx, peer_confirm, SHA256_DIGEST_LENGTH); + + HMAC_Update(hmac_ctx, session->my_confirm, SHA256_DIGEST_LENGTH); + + pwd_hmac_final(hmac_ctx, mk); + + /* stretch the mk with the session-id to get MSK | EMSK */ + eap_pwd_kdf(mk, SHA256_DIGEST_LENGTH, (char const *)session_id, + SHA256_DIGEST_LENGTH + 1, msk_emsk, 1024); /* it's bits, ((64 + 64) * 8) */ + + memcpy(msk, msk_emsk, 64); + memcpy(emsk, msk_emsk + 64, 64); + + HMAC_CTX_free(hmac_ctx); + talloc_free(cruft); + return 0; +} diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h b/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h new file mode 100644 index 0000000..a40a346 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) Dan Harkins, 2012 + * + * Copyright holder grants permission for redistribution and use in source + * and binary forms, with or without modification, provided that the + * following conditions are met: + * 1. Redistribution of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer + * in all source files. + * 2. Redistribution in binary form must retain the above copyright + * notice, this list of conditions, and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * "DISCLAIMER OF LIABILITY + * + * THIS SOFTWARE IS PROVIDED BY DAN HARKINS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INDUSTRIAL LOUNGE BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE." + * + * This license and distribution terms cannot be changed. In other words, + * this code cannot simply be copied and put under a different distribution + * license (including the GNU public license). + */ + +#ifndef _EAP_PWD_H +#define _EAP_PWD_H + +RCSIDH(eap_pwd_h, "$Id$") +#include "eap.h" + +#include <openssl/bn.h> +#include <openssl/sha.h> +#include <openssl/ec.h> +#include <openssl/evp.h> +#include <openssl/hmac.h> + +typedef struct _pwd_hdr { + uint8_t lm_exchange; +#define EAP_PWD_EXCH_ID 1 +#define EAP_PWD_EXCH_COMMIT 2 +#define EAP_PWD_EXCH_CONFIRM 3 +// uint16_t total_length; /* there if the L-bit is set */ + uint8_t data[]; +} CC_HINT(packed) pwd_hdr; + +#define EAP_PWD_GET_LENGTH_BIT(x) ((x)->lm_exchange & 0x80) +#define EAP_PWD_SET_LENGTH_BIT(x) ((x)->lm_exchange |= 0x80) +#define EAP_PWD_GET_MORE_BIT(x) ((x)->lm_exchange & 0x40) +#define EAP_PWD_SET_MORE_BIT(x) ((x)->lm_exchange |= 0x40) +#define EAP_PWD_GET_EXCHANGE(x) ((x)->lm_exchange & 0x3f) +#define EAP_PWD_SET_EXCHANGE(x,y) ((x)->lm_exchange |= (y)) + +typedef struct _pwd_id_packet { + uint16_t group_num; + uint8_t random_function; +#define EAP_PWD_DEF_RAND_FUN 1 + uint8_t prf; +#define EAP_PWD_DEF_PRF 1 + uint8_t token[4]; + uint8_t prep; +#define EAP_PWD_PREP_NONE 0 +#define EAP_PWD_PREP_MS 1 +#define EAP_PWD_PREP_SASL 2 + char identity[]; +} CC_HINT(packed) pwd_id_packet_t; + +typedef struct _pwd_session_t { + uint16_t state; +#define PWD_STATE_ID_REQ 1 +#define PWD_STATE_COMMIT 2 +#define PWD_STATE_CONFIRM 3 + uint16_t group_num; + uint32_t ciphersuite; + uint32_t token; + char peer_id[MAX_STRING_LEN]; + size_t peer_id_len; + size_t mtu; + uint8_t *in; /* reassembled fragments */ + size_t in_pos; + size_t in_len; + uint8_t *out; /* message to fragment */ + size_t out_pos; + size_t out_len; + BN_CTX *bnctx; + EC_GROUP *group; + EC_POINT *pwe; + BIGNUM *order; + BIGNUM *prime; + BIGNUM *k; + BIGNUM *private_value; + BIGNUM *peer_scalar; + BIGNUM *my_scalar; + EC_POINT *my_element; + EC_POINT *peer_element; + uint8_t my_confirm[SHA256_DIGEST_LENGTH]; + uint8_t prep; + uint8_t salt_present; + uint8_t salt_len; + uint8_t salt[255]; +} pwd_session_t; + +int compute_password_element(REQUEST *request, pwd_session_t *sess, uint16_t grp_num, + char const *password, int password_len, + char const *id_server, int id_server_len, + char const *id_peer, int id_peer_len, + uint32_t *token); +int compute_scalar_element(REQUEST *request, pwd_session_t *sess, BN_CTX *bnctx); +int process_peer_commit(REQUEST *request, pwd_session_t *sess, uint8_t *in, size_t in_len, BN_CTX *bnctx); +int compute_server_confirm(REQUEST *request, pwd_session_t *sess, uint8_t *out, BN_CTX *bnctx); +int compute_peer_confirm(REQUEST *request, pwd_session_t *sess, uint8_t *out, BN_CTX *bnctx); +int compute_keys(REQUEST *request, pwd_session_t *sess, uint8_t *peer_confirm, + uint8_t *msk, uint8_t *emsk); +#ifdef PRINTBUF +void print_buf(char *str, uint8_t *buf, int len); +#endif /* PRINTBUF */ + +#endif /* _EAP_PWD_H */ diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c b/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c new file mode 100644 index 0000000..4992a2a --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c @@ -0,0 +1,972 @@ +/* + * Copyright (c) Dan Harkins, 2012 + * + * Copyright holder grants permission for redistribution and use in source + * and binary forms, with or without modification, provided that the + * following conditions are met: + * 1. Redistribution of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer + * in all source files. + * 2. Redistribution in binary form must retain the above copyright + * notice, this list of conditions, and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * "DISCLAIMER OF LIABILITY + * + * THIS SOFTWARE IS PROVIDED BY DAN HARKINS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INDUSTRIAL LOUNGE BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE." + * + * This license and distribution terms cannot be changed. In other words, + * this code cannot simply be copied and put under a different distribution + * license (including the GNU public license). + */ + +RCSID("$Id$") +USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ + +#include "rlm_eap_pwd.h" + +#include "eap_pwd.h" + +#define MPPE_KEY_LEN 32 +#define MSK_EMSK_LEN (2*MPPE_KEY_LEN) + +/* EAP-PWD can use different preprocessing (prep) modes to mangle the password + * before proving to both parties that they both know the same (mangled) password. + * + * The server advertises a preprocessing mode to the client. Only "none" is + * mandatory to implement. + * + * What is a good selection on the preprocessing mode? + * + * a) the server uses a hashed password + * b) the client uses a hashed password + * + * a | b | result + * --+---+--------------------------------------- + * n | n | none + * n | y | hint needed (cannot know automatically) + * y | n | select by hash given + * y | y | only works if both have the same hash; select by hash given + * + * Which hash functions does the server or client need to implement? + * + * a | b | server | client + * --+---+------------------------+---------------------- + * n | n | none | none + * n | y | as configured | none + * y | n | none | as selected by server + * y | y | none | none + * + * RFC 5931 defines 3 and RFC 8146 another 8 hash functions to implement. + * Can we avoid implementing them all? Only if they are provided as hash by some + * other module, e.g. in SQL or statically in password database. + * + * Therefore we select the preprocessing mode by the type of password given if + * in automatic mode: + * a) Cleartext-Password or User-Password: None. + * If the client only supports a hash (e.g. on Windows it might only have an + * NT-Password), do not provide a Cleartext-Password attribute but instead + * preprocess the password externally (e.g. hash the Cleartext-Password + * into an NT-Password and drop the Cleartext-Password). + * b) NT-Password: rfc2759 (prep=MS). + * The NT-Password Hash is hashed into a HashNTPasswordHash hash. + * c) EAP-Pwd-Password-Hash - provides hash as binary + * EAP-Pwd-Password-Salt - (optional) salt to be transmitted to client + * (RFC 8146) + * EAP-Pwd-Password-Prep - constant to transmit to client in prep field + * + * Though, there is one issue left. The method needs to be selected in + * EAP-PWD-ID/Request, that is the first message from server and thus before + * the client sent its peer-id. This is feasable using the EAP-Identity frame + * (outer identity); EAP-PWD does transmit its peer-id in plaintext anyway. + * So we need a toggle for this, in case anybody needs rlm_eap_pwd to use + * only the peer_id (inner identity). This toogle is an integer to also support + * setting currently unknown nor not implemented preprocessing methods. + * + * The toogle is named "prep", is a module configuration item, and accepts the + * following values: + * prep | meaning + * -------+-------------------------------------------------------------------- + * -1 | [automatic] discover using method described above from EAP-Identity + * | as User-Name before EAP-PWD-Id/Request + * 0..255 | [static] Fixed password preprocessing method. Expects virtual + * | server to provide matching password given EAP-PWD + * | peer-id as User-Name. The virtual server is provided + * | with EAP-Pwd-Password-Prep containing the configured + * | prep value. + * else | reserved/invalid + * + * Attributes to provide Password/Password-Hash and possibly salt. + * prep | accepted attributes + * -------+-------------------------------------------------------------------- + * -1 | see above for automatic discovery + * 0 | Use Cleartext-Password or give cleartext in EAP-Pwd-Password-Hash + * 1 | Use NT-Password, Cleartext-Password, User-Password or + * | give hashed NT-Password hash in EAP-Pwd-Password-Hash + * 2..255 | Use EAP-Pwd-Password-Hash and possibly EAP-Pwd-Pasword-Salt. + * + * To be able to pass EAP-Pwd-Password-Hash and EAP-Pwd-Password-Salt als hex + * string, they are decoded as hex if module config option unhex=1 (default). + * Set it to zero if you provide binary input. + */ + +static CONF_PARSER pwd_module_config[] = { + { "group", FR_CONF_OFFSET(PW_TYPE_INTEGER, eap_pwd_t, group), "19" }, + { "fragment_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, eap_pwd_t, fragment_size), "1020" }, + { "server_id", FR_CONF_OFFSET(PW_TYPE_STRING, eap_pwd_t, server_id), NULL }, + { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, eap_pwd_t, virtual_server), NULL }, + { "prep", FR_CONF_OFFSET(PW_TYPE_SIGNED, eap_pwd_t, prep), "0" }, + { "unhex", FR_CONF_OFFSET(PW_TYPE_SIGNED, eap_pwd_t, unhex), "1" }, + CONF_PARSER_TERMINATOR +}; + +static int mod_instantiate (CONF_SECTION *cs, void **instance) +{ + eap_pwd_t *inst; + + *instance = inst = talloc_zero(cs, eap_pwd_t); + if (!inst) return -1; + + if (cf_section_parse(cs, inst, pwd_module_config) < 0) { + return -1; + } + + if (inst->fragment_size < 100) { + cf_log_err_cs(cs, "Fragment size is too small"); + return -1; + } + + if (inst->prep < -1 || inst->prep > 255) { + cf_log_err_cs(cs, "Invalid value for password preparation method: %d", inst->prep); + return -1; + } + + return 0; +} + +static int _free_pwd_session (pwd_session_t *session) +{ + BN_clear_free(session->private_value); + BN_clear_free(session->peer_scalar); + BN_clear_free(session->my_scalar); + BN_clear_free(session->k); + EC_POINT_clear_free(session->my_element); + EC_POINT_clear_free(session->peer_element); + EC_GROUP_free(session->group); + EC_POINT_clear_free(session->pwe); + BN_clear_free(session->order); + BN_clear_free(session->prime); + BN_CTX_free(session->bnctx); + + return 0; +} + +static int send_pwd_request (pwd_session_t *session, EAP_DS *eap_ds) +{ + size_t len; + uint16_t totlen; + pwd_hdr *hdr; + + len = (session->out_len - session->out_pos) + sizeof(pwd_hdr); + rad_assert(len > 0); + eap_ds->request->code = PW_EAP_REQUEST; + eap_ds->request->type.num = PW_EAP_PWD; + eap_ds->request->type.length = (len > session->mtu) ? session->mtu : len; + eap_ds->request->type.data = talloc_zero_array(eap_ds->request, uint8_t, eap_ds->request->type.length); + hdr = (pwd_hdr *)eap_ds->request->type.data; + + switch (session->state) { + case PWD_STATE_ID_REQ: + EAP_PWD_SET_EXCHANGE(hdr, EAP_PWD_EXCH_ID); + break; + + case PWD_STATE_COMMIT: + EAP_PWD_SET_EXCHANGE(hdr, EAP_PWD_EXCH_COMMIT); + break; + + case PWD_STATE_CONFIRM: + EAP_PWD_SET_EXCHANGE(hdr, EAP_PWD_EXCH_CONFIRM); + break; + + default: + ERROR("rlm_eap_pwd: PWD state is invalid. Can't send request"); + return 0; + } + /* + * are we fragmenting? + */ + if (((session->out_len - session->out_pos) + sizeof(pwd_hdr)) > session->mtu) { + EAP_PWD_SET_MORE_BIT(hdr); + if (session->out_pos == 0) { + /* + * the first fragment, add the total length + */ + EAP_PWD_SET_LENGTH_BIT(hdr); + totlen = ntohs(session->out_len); + memcpy(hdr->data, (char *)&totlen, sizeof(totlen)); + memcpy(hdr->data + sizeof(uint16_t), + session->out, + session->mtu - sizeof(pwd_hdr) - sizeof(uint16_t)); + session->out_pos += (session->mtu - sizeof(pwd_hdr) - sizeof(uint16_t)); + } else { + /* + * an intermediate fragment + */ + memcpy(hdr->data, session->out + session->out_pos, (session->mtu - sizeof(pwd_hdr))); + session->out_pos += (session->mtu - sizeof(pwd_hdr)); + } + } else { + /* + * either it's not a fragment or it's the last fragment. + * The out buffer isn't needed anymore though so get rid of it. + */ + memcpy(hdr->data, session->out + session->out_pos, + (session->out_len - session->out_pos)); + talloc_free(session->out); + session->out = NULL; + session->out_pos = session->out_len = 0; + } + return 1; +} + +static void normify(REQUEST *request, VALUE_PAIR *vp) +{ + size_t decoded; + size_t expected_len; + uint8_t *buffer; + + rad_assert((vp->da->type == PW_TYPE_OCTETS) || (vp->da->type == PW_TYPE_STRING)); + + if (vp->vp_length % 2 != 0 || vp->vp_length == 0) return; + + expected_len = vp->vp_length / 2; + buffer = talloc_zero_array(request, uint8_t, expected_len); + rad_assert(buffer); + + decoded = fr_hex2bin(buffer, expected_len, vp->vp_strvalue, vp->vp_length); + if (decoded == expected_len) { + RDEBUG2("Normalizing %s from hex encoding, %zu bytes -> %zu bytes", + vp->da->name, vp->vp_length, decoded); + fr_pair_value_memcpy(vp, buffer, decoded); + } else { + RDEBUG2("Normalizing %s from hex encoding, %zu bytes -> %zu bytes failed, got %zu bytes", + vp->da->name, vp->vp_length, expected_len, decoded); + } + + talloc_free(buffer); +} + +static int fetch_and_process_password(pwd_session_t *session, REQUEST *request, eap_pwd_t *inst) { + REQUEST *fake; + VALUE_PAIR *vp, *pw; + const char *pwbuf; + int pw_len; + uint8_t nthash[MD4_DIGEST_LENGTH]; + uint8_t nthashash[MD4_DIGEST_LENGTH]; + int ret = -1; + eap_type_t old_eap_type = 0; + + if ((fake = request_alloc_fake(request)) == NULL) { + RDEBUG("pwd unable to create fake request!"); + return ret; + } + fake->username = fr_pair_afrom_num(fake->packet, PW_USER_NAME, 0); + if (!fake->username) { + RDEBUG("Failed creating pair for peer id"); + goto out; + } + fr_pair_value_bstrncpy(fake->username, session->peer_id, session->peer_id_len); + fr_pair_add(&fake->packet->vps, fake->username); + + if (inst->prep >= 0) { + vp = fr_pair_afrom_num(fake->packet, PW_EAP_PWD_PASSWORD_PREP, 0); + rad_assert(vp != NULL); + vp->vp_byte = inst->prep; + fr_pair_add(&fake->packet->vps, vp); + } + + if ((vp = fr_pair_find_by_num(request->config, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) { + fake->server = vp->vp_strvalue; + } else if (inst->virtual_server) { + fake->server = inst->virtual_server; + } /* else fake->server == request->server */ + + if ((vp = fr_pair_find_by_num(request->packet->vps, PW_EAP_TYPE, 0, TAG_ANY)) != NULL) { + /* EAP-Type = NAK here if inst->prep == -1. + * But this does not help the virtual server to differentiate + * based on which EAP method was selected, that is to properly + * prepare session-state: for PWD. + * So fake EAP-Type = PWD here for the time of the inner request. + */ + old_eap_type = vp->vp_integer; + vp->vp_integer = PW_EAP_PWD; + } + RDEBUG("Sending tunneled request"); + rdebug_pair_list(L_DBG_LVL_1, request, fake->packet->vps, NULL); + + if (fake->server) { + RDEBUG("server %s {", fake->server); + } else { + RDEBUG("server {"); + } + + /* + * Call authorization recursively, which will + * get the password. + */ + RINDENT(); + process_authorize(0, fake); + REXDENT(); + + /* + * Note that we don't do *anything* with the reply + * attributes. + */ + if (fake->server) { + RDEBUG("} # server %s", fake->server); + } else { + RDEBUG("}"); + } + + RDEBUG("Got tunneled reply code %d", fake->reply->code); + rdebug_pair_list(L_DBG_LVL_1, request, fake->reply->vps, NULL); + + if (old_eap_type && (vp = fr_pair_find_by_num(request->packet->vps, PW_EAP_TYPE, 0, TAG_ANY)) != NULL) { + vp->vp_integer = old_eap_type; + } + + pw = fr_pair_find_by_num(fake->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY); + if (!pw) { + pw = fr_pair_find_by_num(fake->config, PW_USER_PASSWORD, 0, TAG_ANY); + } + + if (pw && (inst->prep < 0 || inst->prep == EAP_PWD_PREP_NONE)) { + VERIFY_VP(pw); + session->prep = EAP_PWD_PREP_NONE; + + RDEBUG("Use Cleartext-Password or User-Password for %s to do pwd authentication", + session->peer_id); + + pwbuf = pw->vp_strvalue; + pw_len = pw->vp_length; + + goto success; + } + + pw = fr_pair_find_by_num(fake->config, PW_NT_PASSWORD, 0, TAG_ANY); + + if (pw && (inst->prep < 0 || inst->prep == EAP_PWD_PREP_MS)) { + VERIFY_VP(pw); + session->prep = EAP_PWD_PREP_MS; + + RDEBUG("Use NT-Password for %s to do pwd authentication", + session->peer_id); + + if (pw->vp_length != MD4_DIGEST_LENGTH) { + RDEBUG("NT-Password invalid length"); + goto out; + } + + fr_md4_calc(nthashash, pw->vp_octets, pw->vp_length); + pwbuf = (const char*) nthashash; + pw_len = MD4_DIGEST_LENGTH; + + goto success; + } + + pw = fr_pair_find_by_num(fake->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY); + if (!pw) { + pw = fr_pair_find_by_num(fake->config, PW_USER_PASSWORD, 0, TAG_ANY); + } + + if (pw && inst->prep == EAP_PWD_PREP_MS) { + VERIFY_VP(pw); + session->prep = EAP_PWD_PREP_NONE; + + RDEBUG("Use Cleartext-Password or User-Password as NT-Password for %s to do pwd authentication", + session->peer_id); + + // compute NT-Hash from Cleartext-Password + ssize_t len; + uint8_t ucs2_password[512]; + len = fr_utf8_to_ucs2(ucs2_password, sizeof(ucs2_password), pw->vp_strvalue, pw->vp_length); + if (len < 0) { + ERROR("rlm_eap_pwd: Error converting password to UCS2"); + goto out; + } + fr_md4_calc(nthash, ucs2_password, len); + + fr_md4_calc(nthashash, nthash, MD4_DIGEST_LENGTH); + pwbuf = (const char*) nthashash; + pw_len = MD4_DIGEST_LENGTH; + + goto success; + } + + vp = fr_pair_find_by_num(fake->config, PW_EAP_PWD_PASSWORD_PREP, 0, TAG_ANY); + if (vp) { + VERIFY_VP(vp); + } + if (vp && inst->prep < 0) { + RDEBUG("Use EAP-Pwd-Password-Prep %u for %s to do pwd authentication", + vp->vp_byte, session->peer_id); + session->prep = vp->vp_byte; + } else if (vp && inst->prep != vp->vp_byte) { + RDEBUG2("Mismatch of configured password preparation method and provided EAP-Pwd-Password-Prep attribute type for %s", + session->peer_id); + goto out; + } else if (inst->prep < 0) { + RDEBUG2("Missing EAP-Pwd-Password-Prep for %s", + session->peer_id); + goto out; + } + + pw = fr_pair_find_by_num(fake->config, PW_EAP_PWD_PASSWORD_SALT, 0, TAG_ANY); + if (pw) { + VERIFY_VP(pw); + + RDEBUG("Use EAP-Pwd-Password-Salt for %s to do pwd authentication", + session->peer_id); + + if (inst->unhex) normify(request, pw); + + if (pw->vp_length > 255) { + /* salt len is 1 byte */ + RDEBUG("EAP-Pwd-Password-Salt too long (more than 255 octets)"); + goto out; + } + rad_assert(pw->vp_length <= sizeof(session->salt)); + + session->salt_present = 1; + session->salt_len = pw->vp_length; + memcpy(session->salt, pw->vp_octets, pw->vp_length); + } + + pw = fr_pair_find_by_num(fake->config, PW_EAP_PWD_PASSWORD_HASH, 0, TAG_ANY); + if (pw) { + VERIFY_VP(pw); + + RDEBUG("Use EAP-Pwd-Password-Hash for %s to do pwd authentication", + session->peer_id); + + if (inst->unhex) normify(request, pw); + + pwbuf = (const char*) pw->vp_octets; + pw_len = pw->vp_length; + + goto success; + } + + RDEBUG2("Mismatch of password preparation method and provided password attribute type for %s", + session->peer_id); + goto out; + +success: + if (RDEBUG_ENABLED4) { + char outbuf[1024]; + char *p = outbuf; + for (int i = 0; i < pw_len && p < outbuf + sizeof(outbuf) - 3; i++) { + p += sprintf(p, "%02hhX", pwbuf[i]); + } + RDEBUG4("hex pw data: %s (%d)", outbuf, pw_len); + } + + if (compute_password_element(request, session, session->group_num, + pwbuf, pw_len, + inst->server_id, strlen(inst->server_id), + session->peer_id, strlen(session->peer_id), + &session->token)) { + RDEBUG("failed to obtain password element"); + goto out; + } + + ret = 0; +out: + talloc_free(fake); + return ret; +} + +static int mod_session_init (void *instance, eap_handler_t *handler) +{ + pwd_session_t *session; + eap_pwd_t *inst = (eap_pwd_t *)instance; + VALUE_PAIR *vp; + pwd_id_packet_t *packet; + REQUEST *request; + + if (!inst || !handler) { + ERROR("rlm_eap_pwd: Initiate, NULL data provided"); + return 0; + } + + request = handler->request; + if (!request) { + ERROR("rlm_eap_pwd: NULL request provided"); + return 0; + } + + /* + * make sure the server's been configured properly + */ + if (!inst->server_id) { + ERROR("rlm_eap_pwd: Server ID is not configured"); + return 0; + } + switch (inst->group) { + case 19: + case 20: + case 21: + case 25: + case 26: + break; + + default: + ERROR("rlm_eap_pwd: Group is not supported"); + return 0; + } + + if ((session = talloc_zero(handler, pwd_session_t)) == NULL) return 0; + talloc_set_destructor(session, _free_pwd_session); + /* + * set things up so they can be free'd reliably + */ + session->group_num = inst->group; + session->private_value = NULL; + session->peer_scalar = NULL; + session->my_scalar = NULL; + session->k = NULL; + session->my_element = NULL; + session->peer_element = NULL; + session->group = NULL; + session->pwe = NULL; + session->order = NULL; + session->prime = NULL; + + session->bnctx = BN_CTX_new(); + if (session->bnctx == NULL) { + ERROR("rlm_eap_pwd: Failed to get BN context"); + return 0; + } + + /* + * The admin can dynamically change the MTU. + */ + session->mtu = inst->fragment_size; + vp = fr_pair_find_by_num(handler->request->packet->vps, PW_FRAMED_MTU, 0, TAG_ANY); + + /* + * session->mtu is *our* MTU. We need to subtract off the EAP + * overhead. + * + * 9 = 4 (EAPOL header) + 4 (EAP header) + 1 (EAP type) + * + * The fragmentation code deals with the included length + * so we don't need to subtract that here. + */ + if (vp && (vp->vp_integer > 100) && (vp->vp_integer < session->mtu)) { + session->mtu = vp->vp_integer - 9; + } + + session->state = PWD_STATE_ID_REQ; + session->in = NULL; + session->out_pos = 0; + handler->opaque = session; + + session->token = fr_rand(); + if (inst->prep < 0) { + RDEBUG2("using outer identity %s to configure EAP-PWD", handler->identity); + session->peer_id_len = strlen(handler->identity); + if (session->peer_id_len >= sizeof(session->peer_id)) { + RDEBUG("identity is malformed"); + return 0; + } + memcpy(session->peer_id, handler->identity, session->peer_id_len); + session->peer_id[session->peer_id_len] = '\0'; + + /* + * make fake request to get the password for the usable ID + * in order to identity prep + */ + if (fetch_and_process_password(session, handler->request, inst) < 0) { + RDEBUG("failed to find password for %s to do pwd authentication (init)", + session->peer_id); + return 0; + } + } else { + session->prep = inst->prep; + } + + /* + * construct an EAP-pwd-ID/Request + */ + session->out_len = sizeof(pwd_id_packet_t) + strlen(inst->server_id); + if ((session->out = talloc_zero_array(session, uint8_t, session->out_len)) == NULL) { + return 0; + } + + packet = (pwd_id_packet_t *)session->out; + packet->group_num = htons(session->group_num); + packet->random_function = EAP_PWD_DEF_RAND_FUN; + packet->prf = EAP_PWD_DEF_PRF; + memcpy(packet->token, (char *)&session->token, 4); + packet->prep = session->prep; + memcpy(packet->identity, inst->server_id, session->out_len - sizeof(pwd_id_packet_t) ); + + handler->stage = PROCESS; + + return send_pwd_request(session, handler->eap_ds); +} + +static int mod_process(void *arg, eap_handler_t *handler) +{ + pwd_session_t *session; + pwd_hdr *hdr; + pwd_id_packet_t *packet; + REQUEST *request; + eap_packet_t *response; + EAP_DS *eap_ds; + size_t in_len, peer_id_len; + int ret = 0; + eap_pwd_t *inst = (eap_pwd_t *)arg; + uint16_t offset; + uint8_t exch, *in, *ptr, msk[MSK_EMSK_LEN], emsk[MSK_EMSK_LEN]; + uint8_t peer_confirm[SHA256_DIGEST_LENGTH]; + char *peer_id; + + if (((eap_ds = handler->eap_ds) == NULL) || !inst) return 0; + + session = (pwd_session_t *)handler->opaque; + request = handler->request; + response = handler->eap_ds->response; + hdr = (pwd_hdr *)response->type.data; + + /* + * The header must be at least one byte. + */ + if (!hdr || (response->type.length < sizeof(pwd_hdr))) { + RDEBUG("Packet with insufficient data"); + return 0; + } + + in = hdr->data; + in_len = response->type.length - sizeof(pwd_hdr); + + /* + * see if we're fragmenting, if so continue until we're done + */ + if (session->out_pos) { + if (in_len) RDEBUG2("pwd got something more than an ACK for a fragment"); + + return send_pwd_request(session, eap_ds); + } + + /* + * the first fragment will have a total length, make a + * buffer to hold all the fragments + */ + if (EAP_PWD_GET_LENGTH_BIT(hdr)) { + if (session->in) { + RDEBUG2("pwd already alloced buffer for fragments"); + return 0; + } + + if (in_len < 2) { + RDEBUG("Invalid packet: length bit set, but no length field"); + return 0; + } + + session->in_len = ntohs(in[0] * 256 | in[1]); + if ((session->in = talloc_zero_array(session, uint8_t, session->in_len)) == NULL) { + RDEBUG2("pwd cannot allocate %zd buffer to hold fragments", + session->in_len); + return 0; + } + memset(session->in, 0, session->in_len); + session->in_pos = 0; + in += sizeof(uint16_t); + in_len -= sizeof(uint16_t); + } + + /* + * all fragments, including the 1st will have the M(ore) bit set, + * buffer those fragments! + */ + if (EAP_PWD_GET_MORE_BIT(hdr)) { + if (!session->in) { + RDEBUG2("Unexpected fragment."); + return 0; + } + + if ((session->in_pos + in_len) > session->in_len) { + RDEBUG2("Fragment overflows packet."); + return 0; + } + + memcpy(session->in + session->in_pos, in, in_len); + session->in_pos += in_len; + + /* + * send back an ACK for this fragment + */ + exch = EAP_PWD_GET_EXCHANGE(hdr); + eap_ds->request->code = PW_EAP_REQUEST; + eap_ds->request->type.num = PW_EAP_PWD; + eap_ds->request->type.length = sizeof(pwd_hdr); + if ((eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, sizeof(pwd_hdr))) == NULL) { + return 0; + } + hdr = (pwd_hdr *)eap_ds->request->type.data; + EAP_PWD_SET_EXCHANGE(hdr, exch); + return 1; + } + + + if (session->in) { + /* + * the last fragment... + */ + if ((session->in_pos + in_len) > session->in_len) { + RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent"); + return 0; + } + memcpy(session->in + session->in_pos, in, in_len); + in = session->in; + in_len = session->in_len; + } + + switch (session->state) { + case PWD_STATE_ID_REQ: + { + BIGNUM *x = NULL, *y = NULL; + + if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_ID) { + RDEBUG2("pwd exchange is incorrect: not ID"); + return 0; + } + + packet = (pwd_id_packet_t *) in; + if (in_len < sizeof(*packet)) { + RDEBUG("Packet is too small (%zd < %zd).", in_len, sizeof(*packet)); + return 0; + } + + if ((packet->prf != EAP_PWD_DEF_PRF) || + (packet->random_function != EAP_PWD_DEF_RAND_FUN) || + (packet->prep != session->prep) || + (CRYPTO_memcmp(packet->token, &session->token, 4)) || + (packet->group_num != ntohs(session->group_num))) { + RDEBUG2("pwd id response is invalid"); + return 0; + } + /* + * we've agreed on the ciphersuite, record it... + */ + ptr = (uint8_t *)&session->ciphersuite; + memcpy(ptr, (char *)&packet->group_num, sizeof(uint16_t)); + ptr += sizeof(uint16_t); + *ptr = EAP_PWD_DEF_RAND_FUN; + ptr += sizeof(uint8_t); + *ptr = EAP_PWD_DEF_PRF; + + peer_id_len = in_len - sizeof(pwd_id_packet_t); + if (peer_id_len >= sizeof(session->peer_id)) { + RDEBUG2("pwd id response is malformed"); + return 0; + } + peer_id = packet->identity; + + if (inst->prep >= 0) { + /* + * make fake request to get the password for the usable ID + */ + + session->peer_id_len = peer_id_len; + memcpy(session->peer_id, peer_id, peer_id_len); + session->peer_id[peer_id_len] = '\0'; + + if (fetch_and_process_password(session, request, inst) < 0) { + RDEBUG2("failed to find password for %s to do pwd authentication", + session->peer_id); + return 0; + } + } else { + /* verify inner identity == outer identity */ + if (session->peer_id_len != peer_id_len || + memcmp(session->peer_id, peer_id, peer_id_len) != 0) { + char buf[sizeof(session->peer_id)]; + memcpy(buf, peer_id, peer_id_len); + buf[peer_id_len] = '\0'; + + RDEBUG2("inner identity(peer_id) %s does not match outer identity %s", + buf, session->peer_id); + return 0; + } + RDEBUG2("inner identity matched for %s", session->peer_id); + } + + /* + * compute our scalar and element + */ + if (compute_scalar_element(request, session, session->bnctx)) { + DEBUG2("failed to compute server's scalar and element"); + return 0; + } + + MEM(x = BN_new()); + MEM(y = BN_new()); + + /* + * element is a point, get both coordinates: x and y + */ + if (!EC_POINT_get_affine_coordinates(session->group, session->my_element, x, y, + session->bnctx)) { + DEBUG2("server point assignment failed"); + BN_clear_free(x); + BN_clear_free(y); + return 0; + } + + /* + * construct request + */ + session->out_len = BN_num_bytes(session->order) + (2 * BN_num_bytes(session->prime)); + if (session->salt_present) + session->out_len += 1 + session->salt_len; + + if ((session->out = talloc_array(session, uint8_t, session->out_len)) == NULL) { + return 0; + } + memset(session->out, 0, session->out_len); + + ptr = session->out; + if (session->salt_present) { + *ptr = session->salt_len; + ptr++; + + memcpy(ptr, session->salt, session->salt_len); + ptr += session->salt_len; + } + + offset = BN_num_bytes(session->prime) - BN_num_bytes(x); + BN_bn2bin(x, ptr + offset); + BN_clear_free(x); + + ptr += BN_num_bytes(session->prime); + offset = BN_num_bytes(session->prime) - BN_num_bytes(y); + BN_bn2bin(y, ptr + offset); + BN_clear_free(y); + + ptr += BN_num_bytes(session->prime); + offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar); + BN_bn2bin(session->my_scalar, ptr + offset); + + session->state = PWD_STATE_COMMIT; + ret = send_pwd_request(session, eap_ds); + } + break; + + case PWD_STATE_COMMIT: + if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_COMMIT) { + RDEBUG2("pwd exchange is incorrect: not commit!"); + return 0; + } + + /* + * process the peer's commit and generate the shared key, k + */ + if (process_peer_commit(request, session, in, in_len, session->bnctx)) { + RDEBUG2("failed to process peer's commit"); + return 0; + } + + /* + * compute our confirm blob + */ + if (compute_server_confirm(request, session, session->my_confirm, session->bnctx)) { + ERROR("rlm_eap_pwd: failed to compute confirm!"); + return 0; + } + + /* + * construct a response...which is just our confirm blob + */ + session->out_len = SHA256_DIGEST_LENGTH; + if ((session->out = talloc_array(session, uint8_t, session->out_len)) == NULL) { + return 0; + } + + memset(session->out, 0, session->out_len); + memcpy(session->out, session->my_confirm, SHA256_DIGEST_LENGTH); + + session->state = PWD_STATE_CONFIRM; + ret = send_pwd_request(session, eap_ds); + break; + + case PWD_STATE_CONFIRM: + if (in_len < SHA256_DIGEST_LENGTH) { + RDEBUG("Peer confirm is too short (%zd < %d)", + in_len, SHA256_DIGEST_LENGTH); + return 0; + } + + if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_CONFIRM) { + RDEBUG2("pwd exchange is incorrect: not commit!"); + return 0; + } + if (compute_peer_confirm(request, session, peer_confirm, session->bnctx)) { + RDEBUG2("pwd exchange cannot compute peer's confirm"); + return 0; + } + if (CRYPTO_memcmp(peer_confirm, in, SHA256_DIGEST_LENGTH)) { + RDEBUG2("pwd exchange fails: peer confirm is incorrect!"); + return 0; + } + if (compute_keys(request, session, peer_confirm, msk, emsk)) { + RDEBUG2("pwd exchange cannot generate (E)MSK!"); + return 0; + } + eap_ds->request->code = PW_EAP_SUCCESS; + /* + * return the MSK (in halves) + */ + eap_add_reply(handler->request, "MS-MPPE-Recv-Key", msk, MPPE_KEY_LEN); + eap_add_reply(handler->request, "MS-MPPE-Send-Key", msk + MPPE_KEY_LEN, MPPE_KEY_LEN); + + ret = 1; + break; + + default: + RDEBUG2("unknown PWD state"); + return 0; + } + + /* + * we processed the buffered fragments, get rid of them + */ + if (session->in) { + talloc_free(session->in); + session->in = NULL; + } + + return ret; +} + +extern rlm_eap_module_t rlm_eap_pwd; +rlm_eap_module_t rlm_eap_pwd = { + .name = "eap_pwd", + .instantiate = mod_instantiate, /* Create new submodule instance */ + .session_init = mod_session_init, /* Create the initial request */ + .process = mod_process, /* Process next round of EAP method */ +}; + diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.h b/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.h new file mode 100644 index 0000000..966646c --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) Dan Harkins, 2012 + * + * Copyright holder grants permission for redistribution and use in source + * and binary forms, with or without modification, provided that the + * following conditions are met: + * 1. Redistribution of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer + * in all source files. + * 2. Redistribution in binary form must retain the above copyright + * notice, this list of conditions, and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * "DISCLAIMER OF LIABILITY + * + * THIS SOFTWARE IS PROVIDED BY DAN HARKINS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INDUSTRIAL LOUNGE BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE." + * + * This license and distribution terms cannot be changed. In other words, + * this code cannot simply be copied and put under a different distribution + * license (including the GNU public license). + */ + +#ifndef _RLM_EAP_PWD_H +#define _RLM_EAP_PWD_H + +#include "eap_pwd.h" + +#include <freeradius-devel/radiusd.h> +#include <freeradius-devel/modules.h> + +typedef struct _eap_pwd_t { + uint32_t group; + uint32_t fragment_size; + char const *server_id; + char const *virtual_server; + int32_t prep; + int32_t unhex; +} eap_pwd_t; + +#endif /* _RLM_EAP_PWD_H */ diff --git a/src/modules/rlm_eap/types/rlm_eap_sim/.gitignore b/src/modules/rlm_eap/types/rlm_eap_sim/.gitignore new file mode 100644 index 0000000..01a5daa --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_sim/.gitignore @@ -0,0 +1 @@ +all.mk diff --git a/src/modules/rlm_eap/types/rlm_eap_sim/all.mk.in b/src/modules/rlm_eap/types/rlm_eap_sim/all.mk.in new file mode 100644 index 0000000..c13b2ef --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_sim/all.mk.in @@ -0,0 +1,12 @@ +TARGETNAME := @targetname@ + +ifneq "$(TARGETNAME)" "" +TARGET := $(TARGETNAME).a +endif + +SOURCES := $(TARGETNAME).c + +SRC_CFLAGS := @mod_cflags@ +TGT_LDLIBS := @mod_ldflags@ +SRC_INCDIRS := ../../ ../../libeap/ +TGT_PREREQS := libfreeradius-eap.a diff --git a/src/modules/rlm_eap/types/rlm_eap_sim/configure b/src/modules/rlm_eap/types/rlm_eap_sim/configure new file mode 100755 index 0000000..ce3205b --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_sim/configure @@ -0,0 +1,2888 @@ +#! /bin/sh +# From configure.ac Revision. +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="rlm_eap_sim.c" +ac_subst_vars='LTLIBOBJS +LIBOBJS +targetname +mod_cflags +mod_ldflags +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +runstatedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_rlm_eap_sim +' + ac_precious_vars='build_alias +host_alias +target_alias' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir runstatedir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --without-rlm_eap_sim build without rlm_eap_sim + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + +# Check whether --with-rlm_eap_sim was given. +if test "${with_rlm_eap_sim+set}" = set; then : + withval=$with_rlm_eap_sim; +fi + + + +fail= +mod_ldflags= +mod_cflags= + +if test x$with_rlm_eap_sim != xno; then + + targetname=rlm_eap_sim +else + targetname= + echo \*\*\* module rlm_eap_sim is disabled. +fi + +if test x"$fail" != x""; then + if test x"${enable_strict_dependencies}" = x"yes"; then + as_fn_error $? "set --without-rlm_eap_sim to disable it explicitly." "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_eap_sim." >&5 +$as_echo "$as_me: WARNING: silently not building rlm_eap_sim." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_eap_sim requires: $fail." >&5 +$as_echo "$as_me: WARNING: FAILURE: rlm_eap_sim requires: $fail." >&2;} + if test x"$headersuggestion" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $headersuggestion" >&5 +$as_echo "$as_me: WARNING: $headersuggestion" >&2;} + fi + if test x"$libsuggestion" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $libsuggestion" >&5 +$as_echo "$as_me: WARNING: $libsuggestion" >&2;} + fi + targetname="" + fi +fi + + + + +ac_config_files="$ac_config_files all.mk" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/src/modules/rlm_eap/types/rlm_eap_sim/configure.ac b/src/modules/rlm_eap/types/rlm_eap_sim/configure.ac new file mode 100644 index 0000000..dceab35 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_sim/configure.ac @@ -0,0 +1,37 @@ +AC_PREREQ([2.68]) +AC_INIT(rlm_eap_sim.c) +AC_REVISION($Revision$) +FR_INIT_MODULE([rlm_eap_sim]) + +fail= +mod_ldflags= +mod_cflags= + +if test x$with_[]modname != xno; then + + targetname=modname +else + targetname= + echo \*\*\* module modname is disabled. +fi + +if test x"$fail" != x""; then + if test x"${enable_strict_dependencies}" = x"yes"; then + AC_MSG_ERROR([set --without-]modname[ to disable it explicitly.]) + else + AC_MSG_WARN([silently not building ]modname[.]) + AC_MSG_WARN([FAILURE: ]modname[ requires: $fail.]) + if test x"$headersuggestion" != x; then + AC_MSG_WARN([$headersuggestion]) + fi + if test x"$libsuggestion" != x; then + AC_MSG_WARN([$libsuggestion]) + fi + targetname="" + fi +fi + +AC_SUBST(mod_ldflags) +AC_SUBST(mod_cflags) +AC_SUBST(targetname) +AC_OUTPUT(all.mk) diff --git a/src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c b/src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c new file mode 100644 index 0000000..38fe997 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c @@ -0,0 +1,697 @@ +/* + * rlm_eap_sim.c Handles that are called from eap for SIM + * + * The development of the EAP/SIM support was funded by Internet Foundation + * Austria (http://www.nic.at/ipa). + * + * 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 Michael Richardson <mcr@sandelman.ottawa.on.ca> + * Copyright 2003,2006 The FreeRADIUS server project + * + */ + +RCSID("$Id$") + +#include <stdio.h> +#include <stdlib.h> + +#include "../../eap.h" +#include "eap_types.h" +#include "eap_sim.h" +#include "comp128.h" + +#include <freeradius-devel/rad_assert.h> + +typedef struct eap_sim_server_state { + enum eapsim_serverstates state; + struct eapsim_keys keys; + int sim_id; +} eap_sim_state_t; + +static int eap_sim_sendstart(eap_handler_t *handler) +{ + VALUE_PAIR **vps, *newvp; + uint16_t words[3]; + eap_sim_state_t *ess; + RADIUS_PACKET *packet; + uint8_t *p; + + rad_assert(handler->request != NULL); + rad_assert(handler->request->reply); + + ess = (eap_sim_state_t *)handler->opaque; + + /* these are the outgoing attributes */ + packet = handler->request->reply; + vps = &packet->vps; + rad_assert(vps != NULL); + + + /* + * Add appropriate TLVs for the EAP things we wish to send. + */ + + /* the version list. We support only version 1. */ + words[0] = htons(sizeof(words[1])); + words[1] = htons(EAP_SIM_VERSION); + words[2] = 0; + + newvp = fr_pair_afrom_num(packet, PW_EAP_SIM_VERSION_LIST, 0); + fr_pair_value_memcpy(newvp, (uint8_t const *) words, sizeof(words)); + + fr_pair_add(vps, newvp); + + /* set the EAP_ID - new value */ + newvp = fr_pair_afrom_num(packet, PW_EAP_ID, 0); + newvp->vp_integer = ess->sim_id++; + fr_pair_replace(vps, newvp); + + /* record it in the ess */ + ess->keys.versionlistlen = 2; + memcpy(ess->keys.versionlist, words + 1, ess->keys.versionlistlen); + + /* the ANY_ID attribute. We do not support re-auth or pseudonym */ + newvp = fr_pair_afrom_num(packet, PW_EAP_SIM_FULLAUTH_ID_REQ, 0); + newvp->vp_length = 2; + newvp->vp_octets = p = talloc_array(newvp, uint8_t, 2); + + p[0] = 0; + p[0] = 1; + fr_pair_add(vps, newvp); + + /* the SUBTYPE, set to start. */ + newvp = fr_pair_afrom_num(packet, PW_EAP_SIM_SUBTYPE, 0); + newvp->vp_integer = EAPSIM_START; + fr_pair_replace(vps, newvp); + + return 1; +} + +static int eap_sim_get_challenge(eap_handler_t *handler, VALUE_PAIR *vps, int idx, eap_sim_state_t *ess) +{ + REQUEST *request = handler->request; + VALUE_PAIR *vp, *ki, *algo_version; + + rad_assert(idx >= 0 && idx < 3); + + /* + * Generate a new RAND value, and derive Kc and SRES from Ki + */ + ki = fr_pair_find_by_num(vps, PW_EAP_SIM_KI, 0, TAG_ANY); + if (ki) { + int i; + + /* + * Check to see if have a Ki for the IMSI, this allows us to generate the rest + * of the triplets. + */ + algo_version = fr_pair_find_by_num(vps, PW_EAP_SIM_ALGO_VERSION, 0, TAG_ANY); + if (!algo_version) { + REDEBUG("Found Ki, but missing EAP-Sim-Algo-Version"); + return 0; + } + + for (i = 0; i < EAPSIM_RAND_SIZE; i++) { + ess->keys.rand[idx][i] = fr_rand(); + } + + switch (algo_version->vp_integer) { + case 1: + comp128v1(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx]); + break; + + case 2: + comp128v23(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx], + true); + break; + + case 3: + comp128v23(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx], + false); + break; + + case 4: + REDEBUG("Comp128-4 algorithm is not supported as details have not yet been published. " + "If you have details of this algorithm please contact the FreeRADIUS " + "maintainers"); + return 0; + + default: + REDEBUG("Unknown/unsupported algorithm Comp128-%i", algo_version->vp_integer); + } + + if (RDEBUG_ENABLED2) { + char buffer[33]; /* 32 hexits (16 bytes) + 1 */ + char *p; + + RDEBUG2("Generated following triplets for round %i:", idx); + + RINDENT(); + p = buffer; + for (i = 0; i < EAPSIM_RAND_SIZE; i++) { + p += sprintf(p, "%02x", ess->keys.rand[idx][i]); + } + RDEBUG2("RAND : 0x%s", buffer); + + p = buffer; + for (i = 0; i < EAPSIM_SRES_SIZE; i++) { + p += sprintf(p, "%02x", ess->keys.sres[idx][i]); + } + RDEBUG2("SRES : 0x%s", buffer); + + p = buffer; + for (i = 0; i < EAPSIM_KC_SIZE; i++) { + p += sprintf(p, "%02x", ess->keys.Kc[idx][i]); + } + RDEBUG2("Kc : 0x%s", buffer); + REXDENT(); + } + return 1; + } + + /* + * Use known RAND, SRES, and Kc values, these may of been pulled in from an AuC, + * or created by sending challenges to the SIM directly. + */ + vp = fr_pair_find_by_num(vps, PW_EAP_SIM_RAND1 + idx, 0, TAG_ANY); + /* Hack for backwards compatibility */ + if (!vp) { + vp = fr_pair_find_by_num(request->reply->vps, PW_EAP_SIM_RAND1 + idx, 0, TAG_ANY); + } + if (!vp) { + /* bad, we can't find stuff! */ + REDEBUG("EAP-SIM-RAND%i not found", idx + 1); + return 0; + } + if (vp->vp_length != EAPSIM_RAND_SIZE) { + REDEBUG("EAP-SIM-RAND%i is not " STRINGIFY(EAPSIM_RAND_SIZE) " bytes, got %zu bytes", + idx + 1, vp->vp_length); + return 0; + } + memcpy(ess->keys.rand[idx], vp->vp_strvalue, EAPSIM_RAND_SIZE); + + vp = fr_pair_find_by_num(vps, PW_EAP_SIM_SRES1 + idx, 0, TAG_ANY); + /* Hack for backwards compatibility */ + if (!vp) { + vp = fr_pair_find_by_num(request->reply->vps, PW_EAP_SIM_SRES1 + idx, 0, TAG_ANY); + } + if (!vp) { + /* bad, we can't find stuff! */ + REDEBUG("EAP-SIM-SRES%i not found", idx + 1); + return 0; + } + + if (vp->vp_length != EAPSIM_SRES_SIZE) { + REDEBUG("EAP-SIM-SRES%i is not " STRINGIFY(EAPSIM_SRES_SIZE) " bytes, got %zu bytes", + idx + 1, vp->vp_length); + return 0; + } + memcpy(ess->keys.sres[idx], vp->vp_strvalue, EAPSIM_SRES_SIZE); + + vp = fr_pair_find_by_num(vps, PW_EAP_SIM_KC1 + idx, 0, TAG_ANY); + /* Hack for backwards compatibility */ + if (!vp) { + vp = fr_pair_find_by_num(request->reply->vps, PW_EAP_SIM_KC1 + idx, 0, TAG_ANY); + } + + if (!vp) { + /* bad, we can't find stuff! */ + REDEBUG("EAP-SIM-Kc%i not found", idx + 1); + return 0; + } + if (vp->vp_length != EAPSIM_KC_SIZE) { + REDEBUG("EAP-SIM-Kc%i is not " STRINGIFY(EAPSIM_KC_SIZE) " bytes, got %zu bytes", + idx + 1, vp->vp_length); + return 0; + } + memcpy(ess->keys.Kc[idx], vp->vp_strvalue, EAPSIM_KC_SIZE); + + return 1; +} + +/** Send the challenge itself + * + * Challenges will come from one of three places eventually: + * + * 1 from attributes like PW_EAP_SIM_RANDx + * (these might be retrieved from a database) + * + * 2 from internally implemented SIM authenticators + * (a simple one based upon XOR will be provided) + * + * 3 from some kind of SS7 interface. + * + * For now, they only come from attributes. + * It might be that the best way to do 2/3 will be with a different + * module to generate/calculate things. + * + */ +static int eap_sim_sendchallenge(eap_handler_t *handler) +{ + REQUEST *request = handler->request; + eap_sim_state_t *ess; + VALUE_PAIR **invps, **outvps, *newvp; + RADIUS_PACKET *packet; + uint8_t *p; + + ess = (eap_sim_state_t *)handler->opaque; + rad_assert(handler->request != NULL); + rad_assert(handler->request->reply); + + /* + * Invps is the data from the client but this is for non-protocol data here. + * We should already have consumed any client originated data. + */ + invps = &handler->request->packet->vps; + + /* + * Outvps is the data to the client + */ + packet = handler->request->reply; + outvps = &packet->vps; + + if (RDEBUG_ENABLED2) { + RDEBUG2("EAP-SIM decoded packet"); + rdebug_pair_list(L_DBG_LVL_2, request, *invps, NULL); + } + + /* + * Okay, we got the challenges! Put them into an attribute. + */ + newvp = fr_pair_afrom_num(packet, PW_EAP_SIM_RAND, 0); + newvp->vp_length = 2 + (EAPSIM_RAND_SIZE * 3); + newvp->vp_octets = p = talloc_array(newvp, uint8_t, newvp->vp_length); + + memset(p, 0, 2); /* clear reserved bytes */ + p += 2; + memcpy(p, ess->keys.rand[0], EAPSIM_RAND_SIZE); + p += EAPSIM_RAND_SIZE; + memcpy(p, ess->keys.rand[1], EAPSIM_RAND_SIZE); + p += EAPSIM_RAND_SIZE; + memcpy(p, ess->keys.rand[2], EAPSIM_RAND_SIZE); + fr_pair_add(outvps, newvp); + + /* + * Set the EAP_ID - new value + */ + newvp = fr_pair_afrom_num(packet, PW_EAP_ID, 0); + newvp->vp_integer = ess->sim_id++; + fr_pair_replace(outvps, newvp); + + /* + * Make a copy of the identity + */ + ess->keys.identitylen = strlen(handler->identity); + memcpy(ess->keys.identity, handler->identity, ess->keys.identitylen); + + /* + * Use the SIM identity, if available + */ + newvp = fr_pair_find_by_num(*invps, PW_EAP_SIM_IDENTITY, 0, TAG_ANY); + if (newvp && newvp->vp_length > 2) { + uint16_t len; + + memcpy(&len, newvp->vp_octets, sizeof(uint16_t)); + len = ntohs(len); + if (len <= newvp->vp_length - 2 && len <= MAX_STRING_LEN) { + ess->keys.identitylen = len; + memcpy(ess->keys.identity, newvp->vp_octets + 2, ess->keys.identitylen); + } + } + + /* + * All set, calculate keys! + */ + eapsim_calculate_keys(&ess->keys); + +#ifdef EAP_SIM_DEBUG_PRF + eapsim_dump_mk(&ess->keys); +#endif + + /* + * Need to include an AT_MAC attribute so that it will get + * calculated. The NONCE_MT and the MAC are both 16 bytes, so + * We store the NONCE_MT in the MAC for the encoder, which + * will pull it out before it does the operation. + */ + newvp = fr_pair_afrom_num(packet, PW_EAP_SIM_MAC, 0); + fr_pair_value_memcpy(newvp, ess->keys.nonce_mt, 16); + fr_pair_replace(outvps, newvp); + + newvp = fr_pair_afrom_num(packet, PW_EAP_SIM_KEY, 0); + fr_pair_value_memcpy(newvp, ess->keys.K_aut, 16); + fr_pair_replace(outvps, newvp); + + /* the SUBTYPE, set to challenge. */ + newvp = fr_pair_afrom_num(packet, PW_EAP_SIM_SUBTYPE, 0); + newvp->vp_integer = EAPSIM_CHALLENGE; + fr_pair_replace(outvps, newvp); + + return 1; +} + +#ifndef EAPTLS_MPPE_KEY_LEN +#define EAPTLS_MPPE_KEY_LEN 32 +#endif + +/* + * this code sends the success message. + * + * the only work to be done is the add the appropriate SEND/RECV + * radius attributes derived from the MSK. + * + */ +static int eap_sim_sendsuccess(eap_handler_t *handler) +{ + unsigned char *p; + eap_sim_state_t *ess; + VALUE_PAIR *vp; + RADIUS_PACKET *packet; + + /* outvps is the data to the client. */ + packet = handler->request->reply; + ess = (eap_sim_state_t *)handler->opaque; + + /* set the EAP_ID - new value */ + vp = fr_pair_afrom_num(packet, PW_EAP_ID, 0); + vp->vp_integer = ess->sim_id++; + fr_pair_replace(&handler->request->reply->vps, vp); + + p = ess->keys.msk; + eap_add_reply(handler->request, "MS-MPPE-Recv-Key", p, EAPTLS_MPPE_KEY_LEN); + p += EAPTLS_MPPE_KEY_LEN; + eap_add_reply(handler->request, "MS-MPPE-Send-Key", p, EAPTLS_MPPE_KEY_LEN); + + return 1; +} + + +/** Run the server state machine + * + */ +static void eap_sim_state_enter(REQUEST *request, eap_handler_t *handler, + eap_sim_state_t *ess, + enum eapsim_serverstates newstate) +{ + switch (newstate) { + /* + * Send the EAP-SIM Start message, listing the versions that we support. + */ + case EAPSIM_SERVER_START: + eap_sim_sendstart(handler); + break; + /* + * Send the EAP-SIM Challenge message. + */ + case EAPSIM_SERVER_CHALLENGE: + eap_sim_sendchallenge(handler); + break; + + /* + * Send the EAP Success message + */ + case EAPSIM_SERVER_SUCCESS: + eap_sim_sendsuccess(handler); + handler->eap_ds->request->code = PW_EAP_SUCCESS; + break; + /* + * Nothing to do for this transition. + */ + default: + + break; + } + + ess->state = newstate; + + /* build the target packet */ + /* we will set the ID on requests, since we have to HMAC it */ + handler->eap_ds->set_request_id = 1; + + if (!map_eapsim_basictypes(handler->request->reply, + handler->eap_ds->request)) { + REDEBUG("Failed encoding EAP-SIM packet"); + } +} + +/* + * Initiate the EAP-SIM session by starting the state machine + * and initiating the state. + */ +static int mod_session_init(UNUSED void *instance, eap_handler_t *handler) +{ + REQUEST *request = handler->request; + eap_sim_state_t *ess; + time_t n; + + ess = talloc_zero(handler, eap_sim_state_t); + if (!ess) { + RDEBUG2("No space for EAP-SIM state"); + return 0; + } + + handler->opaque = ess; + handler->stage = PROCESS; + + /* + * Save the keying material, because it could change on a subsequent retrival. + */ + 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; /* already printed error */ + } + + /* + * This value doesn't have be strong, but it is good if it is different now and then. + */ + time(&n); + ess->sim_id = (n & 0xff); + + eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_START); + + return 1; +} + + +/** Process an EAP-Sim/Response/Start + * + * Verify that client chose a version, and provided a NONCE_MT, + * and if so, then change states to challenge, and send the new + * challenge, else, resend the Request/Start. + */ +static int process_eap_sim_start(eap_handler_t *handler, VALUE_PAIR *vps) +{ + REQUEST *request = handler->request; + VALUE_PAIR *nonce_vp, *selectedversion_vp; + eap_sim_state_t *ess; + uint16_t simversion; + ess = (eap_sim_state_t *)handler->opaque; + + nonce_vp = fr_pair_find_by_num(vps, PW_EAP_SIM_NONCE_MT, 0, TAG_ANY); + 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_state_enter(request, handler, ess, EAPSIM_SERVER_START); + return 1; + } + + /* + * Okay, good got stuff that we need. Check the version we found. + */ + if (selectedversion_vp->vp_length < 2) { + REDEBUG("EAP-SIM version field is too short"); + return 0; + } + memcpy(&simversion, selectedversion_vp->vp_strvalue, sizeof(simversion)); + simversion = ntohs(simversion); + if(simversion != EAP_SIM_VERSION) { + REDEBUG("EAP-SIM version %i is unknown", simversion); + return 0; + } + + /* + * Record it for later keying + */ + memcpy(ess->keys.versionselect, selectedversion_vp->vp_strvalue, sizeof(ess->keys.versionselect)); + + /* + * Double check the nonce size. + */ + if(nonce_vp->vp_length != 18) { + REDEBUG("EAP-SIM nonce_mt must be 16 bytes (+2 bytes padding), not %zu", nonce_vp->vp_length); + return 0; + } + memcpy(ess->keys.nonce_mt, nonce_vp->vp_strvalue + 2, 16); + + /* + * Everything looks good, change states + */ + eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_CHALLENGE); + + return 1; +} + + +/** Process an EAP-Sim/Response/Challenge + * + * Verify that MAC that we received matches what we would have + * calculated from the packet with the SRESx appended. + * + */ +static int process_eap_sim_challenge(eap_handler_t *handler, VALUE_PAIR *vps) +{ + REQUEST *request = handler->request; + eap_sim_state_t *ess = handler->opaque; + + uint8_t srescat[EAPSIM_SRES_SIZE * 3]; + uint8_t *p = srescat; + + uint8_t calcmac[EAPSIM_CALCMAC_SIZE]; + + memcpy(p, ess->keys.sres[0], EAPSIM_SRES_SIZE); + p += EAPSIM_SRES_SIZE; + memcpy(p, ess->keys.sres[1], EAPSIM_SRES_SIZE); + p += EAPSIM_SRES_SIZE; + memcpy(p, ess->keys.sres[2], EAPSIM_SRES_SIZE); + + /* + * Verify the MAC, now that we have all the keys + */ + if (eapsim_checkmac(handler, vps, ess->keys.K_aut, srescat, sizeof(srescat), calcmac)) { + RDEBUG2("MAC check succeed"); + } else { + int i, j; + char macline[20*3]; + char *m = macline; + + j=0; + for (i = 0; i < EAPSIM_CALCMAC_SIZE; i++) { + if(j==4) { + *m++ = '_'; + j=0; + } + j++; + + sprintf(m, "%02x", calcmac[i]); + m = m + strlen(m); + } + REDEBUG("Calculated MAC (%s) did not match", macline); + return 0; + } + + /* everything looks good, change states */ + eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_SUCCESS); + return 1; +} + + +/** Authenticate a previously sent challenge + * + */ +static int mod_process(UNUSED void *arg, eap_handler_t *handler) +{ + REQUEST *request = handler->request; + eap_sim_state_t *ess = handler->opaque; + + VALUE_PAIR *vp, *vps; + + enum eapsim_subtype subtype; + + int success; + + /* + * VPS is the data from the client + */ + vps = handler->request->packet->vps; + + success = unmap_eapsim_basictypes(handler->request->packet, + handler->eap_ds->response->type.data, + handler->eap_ds->response->type.length); + + if (!success) { + REDEBUG("Failed decoding EAP-SIM packet: %s", fr_strerror()); + return 0; + } + + /* + * See what kind of message we have gotten + */ + vp = fr_pair_find_by_num(vps, PW_EAP_SIM_SUBTYPE, 0, TAG_ANY); + if (!vp) { + REDEBUG2("No subtype attribute was created, message dropped"); + return 0; + } + subtype = vp->vp_integer; + + /* + * Client error supersedes anything else. + */ + if (subtype == EAPSIM_CLIENT_ERROR) { + return 0; + } + + switch (ess->state) { + case EAPSIM_SERVER_START: + switch (subtype) { + /* + * Pretty much anything else here is illegal, so we will retransmit the request. + */ + default: + + eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_START); + return 1; + /* + * A response to our EAP-Sim/Request/Start! + */ + case EAPSIM_START: + return process_eap_sim_start(handler, vps); + } + + case EAPSIM_SERVER_CHALLENGE: + switch (subtype) { + /* + * Pretty much anything else here is illegal, so we will retransmit the request. + */ + default: + eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_CHALLENGE); + return 1; + /* + * A response to our EAP-Sim/Request/Challenge! + */ + case EAPSIM_CHALLENGE: + return process_eap_sim_challenge(handler, vps); + } + + default: + rad_assert(0 == 1); + } + + return 0; +} + +/* + * The module name should be the only globally exported symbol. + * That is, everything else should be 'static'. + */ +extern rlm_eap_module_t rlm_eap_sim; +rlm_eap_module_t rlm_eap_sim = { + .name = "eap_sim", + .session_init = mod_session_init, /* Initialise a new EAP session */ + .process = mod_process, /* Process next round of EAP method */ +}; diff --git a/src/modules/rlm_eap/types/rlm_eap_tls/all.mk b/src/modules/rlm_eap/types/rlm_eap_tls/all.mk new file mode 100644 index 0000000..fdb7c4b --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_tls/all.mk @@ -0,0 +1,10 @@ +TARGETNAME := rlm_eap_tls + +ifneq "$(OPENSSL_LIBS)" "" +TARGET := $(TARGETNAME).a +endif + +SOURCES := $(TARGETNAME).c + +SRC_INCDIRS := ../../ ../../libeap/ +TGT_PREREQS := libfreeradius-eap.a diff --git a/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c b/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c new file mode 100644 index 0000000..d327c57 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c @@ -0,0 +1,303 @@ +/* + * rlm_eap_tls.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 2001 hereUare Communications, Inc. <raghud@hereuare.com> + * Copyright 2003 Alan DeKok <aland@freeradius.org> + * Copyright 2006 The FreeRADIUS server project + * + */ + +RCSID("$Id$") +USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ + +#ifdef HAVE_OPENSSL_RAND_H +#include <openssl/rand.h> +#endif + +#ifdef HAVE_OPENSSL_EVP_H +#include <openssl/evp.h> +#endif + +#include "rlm_eap_tls.h" + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +static CONF_PARSER module_config[] = { + { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_tls_t, tls_conf_name), NULL }, + { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_tls_t, virtual_server), NULL }, + { "configurable_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_tls_t, configurable_client_cert), NULL }, + CONF_PARSER_TERMINATOR +}; + + +/* + * Attach the EAP-TLS module. + */ +static int mod_instantiate(CONF_SECTION *cs, void **instance) +{ + rlm_eap_tls_t *inst; + + /* + * Parse the config file & get all the configured values + */ + *instance = inst = talloc_zero(cs, rlm_eap_tls_t); + if (!inst) return -1; + + if (cf_section_parse(cs, inst, module_config) < 0) { + return -1; + } + + inst->tls_conf = eaptls_conf_parse(cs, "tls"); + + if (!inst->tls_conf) { + ERROR("rlm_eap_tls: Failed initializing SSL context"); + return -1; + } + +#ifdef TLS1_3_VERSION + if ((inst->tls_conf->max_version == TLS1_3_VERSION) || + (inst->tls_conf->min_version == TLS1_3_VERSION)) { + WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + WARN("!! Most supplicants do not support EAP-TLS with TLS 1.3"); + WARN("!! Please set tls_max_version = \"1.2\""); + WARN("!! FreeRADIUS only supports TLS 1.3 for special builds of wpa_supplicant and Windows"); + WARN("!! This limitation is likely to change in late 2021."); + WARN("!! If you are using this version of FreeRADIUS after 2021, you will probably need to upgrade"); + WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + } +#endif + + return 0; +} + + +/* + * 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 status; + tls_session_t *ssn; + rlm_eap_tls_t *inst; + REQUEST *request = handler->request; + bool require_client_cert = true; + + inst = type_arg; + + handler->tls = true; + + /* + * Respect EAP-TLS-Require-Client-Cert, but only if + * enabled in the module configuration. + * + * We can't change behavior of existing systems, so this + * change has to be enabled via a new configuration + * option. + */ + if (inst->configurable_client_cert) { + VALUE_PAIR *vp; + + vp = fr_pair_find_by_num(handler->request->config, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY); + if (vp && !vp->vp_integer) require_client_cert = false; + } + + /* + * EAP-TLS always requires a client certificate, and + * allows for TLS 1.3 if permitted. + */ + ssn = eaptls_session(handler, inst->tls_conf, require_client_cert, true); + if (!ssn) { + return 0; + } + + handler->opaque = ((void *)ssn); + ssn->quick_session_tickets = true; /* send as soon as we've seen the client cert */ + + /* + * TLS session initialization is over. Now handle TLS + * related handshaking or application data. + */ + status = eaptls_start(handler->eap_ds, ssn->peap_flag); + if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) { + REDEBUG("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } else { + RDEBUG3("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } + if (status == 0) return 0; + + /* + * The next stage to process the packet. + */ + handler->stage = PROCESS; + + return 1; +} + +/* + * Do authentication, by letting EAP-TLS do most of the work. + */ +static int CC_HINT(nonnull) mod_process(void *type_arg, eap_handler_t *handler) +{ + fr_tls_status_t status; + int ret; + tls_session_t *tls_session = (tls_session_t *) handler->opaque; + REQUEST *request = handler->request; + rlm_eap_tls_t *inst; + + inst = type_arg; + + 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 { + RDEBUG3("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } + + + /* + * Make request available to any SSL callbacks + */ + SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, request); + switch (status) { + /* + * EAP-TLS handshake was successful, return an + * EAP-TLS-Success packet here. + * + * If a virtual server was configured, check that + * it accepts the certificates, too. + */ + case FR_TLS_SUCCESS: + if (inst->virtual_server) { + VALUE_PAIR *vp; + REQUEST *fake; + + /* create a fake request */ + fake = request_alloc_fake(request); + rad_assert(!fake->packet->vps); + + fake->packet->vps = fr_pair_list_copy(fake->packet, request->packet->vps); + + /* set the virtual server to use */ + if ((vp = fr_pair_find_by_num(request->config, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) { + fake->server = vp->vp_strvalue; + } else { + fake->server = inst->virtual_server; + } + + RDEBUG2("Validating certificate"); + rad_virtual_server(fake); + + /* copy the reply vps back to our reply */ + fr_pair_list_mcopy_by_num(request->reply, &request->reply->vps, + &fake->reply->vps, 0, 0, TAG_ANY); + + /* reject if virtual server didn't return accept */ + if (fake->reply->code != PW_CODE_ACCESS_ACCEPT) { + RDEBUG2("Certificate rejected by the virtual server"); + talloc_free(fake); + eaptls_fail(handler, 0); + ret = 0; + goto done; + } + + talloc_free(fake); + /* success */ + } + + /* + * Set the label to a fixed string. For TLS 1.3, + * the label is the same for all TLS-based EAP + * methods. + */ + tls_session->label = "client EAP encryption"; + + /* + * Success: Automatically return MPPE keys. + */ + ret = eaptls_success(handler, 0); + break; + + /* + * The TLS code is still working on the TLS + * exchange, and it's a valid TLS request. + * do nothing. + */ + case FR_TLS_HANDLED: + ret = 1; + break; + + /* + * Handshake is done, proceed with decoding tunneled + * data. + */ + case FR_TLS_OK: + RDEBUG2("Received unexpected tunneled data after successful handshake"); +#ifndef NDEBUG + if ((rad_debug_lvl > 2) && fr_log_fp) { + unsigned int i; + unsigned int data_len; + unsigned char buffer[1024]; + + data_len = (tls_session->record_minus)(&tls_session->dirty_in, + buffer, sizeof(buffer)); + DEBUG(" Tunneled data (%u bytes)", data_len); + for (i = 0; i < data_len; i++) { + if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, " %x: ", i); + if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n"); + + fprintf(fr_log_fp, "%02x ", buffer[i]); + } + fprintf(fr_log_fp, "\n"); + } +#endif + + eaptls_fail(handler, 0); + ret = 0; + break; + + /* + * Anything else: fail. + * + * Also, remove the session from the cache so that + * the client can't re-use it. + */ + default: + tls_fail(tls_session); + ret = 0; + } + +done: + SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, NULL); + + return ret; +} + +/* + * The module name should be the only globally exported symbol. + * That is, everything else should be 'static'. + */ +extern rlm_eap_module_t rlm_eap_tls; +rlm_eap_module_t rlm_eap_tls = { + .name = "eap_tls", + .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 */ +}; diff --git a/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.h b/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.h new file mode 100644 index 0000000..550cbbd --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.h @@ -0,0 +1,52 @@ +/* + * rlm_eap_tls.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 2001 hereUare Communications, Inc. <raghud@hereuare.com> + * Copyright 2003 Alan DeKok <aland@freeradius.org> + * Copyright 2006 The FreeRADIUS server project + */ +#ifndef _RLM_EAP_TLS_H +#define _RLM_EAP_TLS_H + +RCSIDH(rlm_eap_tls_h, "$Id$") + +#include <freeradius-devel/radiusd.h> +#include <freeradius-devel/modules.h> + +#include "eap_tls.h" + +typedef struct rlm_eap_tls_t { + /* + * TLS configuration + */ + char const *tls_conf_name; + fr_tls_server_conf_t *tls_conf; + + /* + * Virtual server for checking certificates + */ + char const *virtual_server; + + /* + * Configurable EAP-TLS-Require-Client-Cert + */ + bool configurable_client_cert; +} rlm_eap_tls_t; + +#endif /* _RLM_EAP_TLS_H */ diff --git a/src/modules/rlm_eap/types/rlm_eap_tnc/.gitignore b/src/modules/rlm_eap/types/rlm_eap_tnc/.gitignore new file mode 100644 index 0000000..01a5daa --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_tnc/.gitignore @@ -0,0 +1 @@ +all.mk diff --git a/src/modules/rlm_eap/types/rlm_eap_tnc/all.mk.in b/src/modules/rlm_eap/types/rlm_eap_tnc/all.mk.in new file mode 100644 index 0000000..59b902e --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_tnc/all.mk.in @@ -0,0 +1,14 @@ +TARGETNAME := @targetname@ + +ifneq "$(TARGETNAME)" "" +TARGET := $(TARGETNAME).a +endif + +SOURCES := $(TARGETNAME).c + +SRC_CFLAGS := @mod_cflags@ +TGT_LDLIBS := @mod_ldflags@ + +SRC_INCDIRS := ../../ ../../libeap/ +TGT_PREREQS := libfreeradius-eap.a + diff --git a/src/modules/rlm_eap/types/rlm_eap_tnc/configure b/src/modules/rlm_eap/types/rlm_eap_tnc/configure new file mode 100755 index 0000000..b3a35d0 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_tnc/configure @@ -0,0 +1,4137 @@ +#! /bin/sh +# From configure.ac Revision. +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="rlm_eap_tnc.c" +ac_subst_vars='LTLIBOBJS +LIBOBJS +targetname +mod_cflags +mod_ldflags +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +runstatedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_rlm_eap_tnc +with_eap_tnc_include_dir +with_eap_tnc_lib_dir +with_eap_tnc_dir +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir runstatedir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --without-rlm_eap_tnc build without rlm_eap_tnc + --with-eap-tnc-include-dir=DIR + Directory where the libtnc includes may be found + --with-eap-tnc-lib-dir=DIR + Directory where the libtnc libraries may be found + --with-eap-tnc-dir=DIR Base directory where libtnc is installed + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + +# Check whether --with-rlm_eap_tnc was given. +if test "${with_rlm_eap_tnc+set}" = set; then : + withval=$with_rlm_eap_tnc; +fi + + + +if test x$with_rlm_eap_tnc != xno; then + eap_tnc_include_dir= + +# Check whether --with-eap-tnc-include-dir was given. +if test "${with_eap_tnc_include_dir+set}" = set; then : + withval=$with_eap_tnc_include_dir; case "$withval" in + no) + as_fn_error $? "Need eap-tnc-include-dir" "$LINENO" 5 + ;; + yes) + ;; + *) + eap_tnc_include_dir="$withval" + ;; + esac +fi + + + eap_tnc_lib_dir= + +# Check whether --with-eap-tnc-lib-dir was given. +if test "${with_eap_tnc_lib_dir+set}" = set; then : + withval=$with_eap_tnc_lib_dir; case "$withval" in + no) + as_fn_error $? "Need eap-tnc-lib-dir" "$LINENO" 5 + ;; + yes) + ;; + *) + eap_tnc_lib_dir="$withval" + ;; + esac +fi + + + +# Check whether --with-eap-tnc-dir was given. +if test "${with_eap_tnc_dir+set}" = set; then : + withval=$with_eap_tnc_dir; case "$withval" in + no) + as_fn_error $? "Need eap-tnc-dir" "$LINENO" 5 + ;; + yes) + ;; + *) + eap_tnc_lib_dir="$withval/lib" + eap_tnc_include_dir="$withval/include" + ;; + esac +fi + + + smart_try_dir="$eap_tnc_include_dir" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + +ac_safe=`echo "naaeap/naaeap.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 naaeap/naaeap.h in $try" >&5 +$as_echo_n "checking for naaeap/naaeap.h in $try... " >&6; } + CPPFLAGS="-isystem $try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <naaeap/naaeap.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}/naaeap/naaeap.h" >&5 +$as_echo_n "checking for ${_prefix}/naaeap/naaeap.h... " >&6; } + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <naaeap/naaeap.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 naaeap/naaeap.h" >&5 +$as_echo_n "checking for naaeap/naaeap.h... " >&6; } + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <naaeap/naaeap.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 try in $_smart_include_dir; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for naaeap/naaeap.h in $try" >&5 +$as_echo_n "checking for naaeap/naaeap.h in $try... " >&6; } + CPPFLAGS="-isystem $try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include <naaeap/naaeap.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_naaeap_naaeap_h" != "xyes"; then + fail="$fail naaeap.h" + fi + + + smart_try_dir="$eap_tnc_lib_dir" + + +sm_lib_safe=`echo "naaeap" | sed 'y%./+-%__p_%'` +sm_func_safe=`echo "processEAPTNCData" | sed 'y%./+-%__p_%'` + +old_LIBS="$LIBS" +old_CPPFLAGS="$CPPFLAGS" +smart_lib= +smart_ldflags= +smart_lib_dir= + +if test "x$smart_try_dir" != "x"; then + for try in $smart_try_dir; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for processEAPTNCData in -lnaaeap in $try" >&5 +$as_echo_n "checking for processEAPTNCData in -lnaaeap in $try... " >&6; } + LIBS="-lnaaeap $old_LIBS" + CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char processEAPTNCData(); +int +main () +{ +processEAPTNCData() + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + smart_lib="-lnaaeap" + smart_ldflags="-L$try -Wl,-rpath,$try" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + break + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + LIBS="$old_LIBS" + CPPFLAGS="$old_CPPFLAGS" +fi + +if test "x$smart_lib" = "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for processEAPTNCData in -lnaaeap" >&5 +$as_echo_n "checking for processEAPTNCData in -lnaaeap... " >&6; } + LIBS="-lnaaeap $old_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char processEAPTNCData(); +int +main () +{ +processEAPTNCData() + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + smart_lib="-lnaaeap" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$old_LIBS" +fi + +if test "x$smart_lib" = "x"; then + for try in /usr/local/lib /opt/lib; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for processEAPTNCData in -lnaaeap in $try" >&5 +$as_echo_n "checking for processEAPTNCData in -lnaaeap in $try... " >&6; } + LIBS="-lnaaeap $old_LIBS" + CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char processEAPTNCData(); +int +main () +{ +processEAPTNCData() + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + smart_lib="-lnaaeap" + smart_ldflags="-L$try -Wl,-rpath,$try" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + break + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + LIBS="$old_LIBS" + CPPFLAGS="$old_CPPFLAGS" +fi + +if test "x$smart_lib" != "x"; then + eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes" + LIBS="$smart_ldflags $smart_lib $old_LIBS" + SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS" +fi + + if test "x$ac_cv_lib_naaeap_processEAPTNCData" != "xyes"; then + fail="$fail libnaaeap" + fi + + targetname=rlm_eap_tnc # keep this! Don't change! +else + targetname= # keep this! Don't change! + echo \*\*\* module rlm_eap_tnc is disabled. # keep this! Don't change! +fi + +if test x"$fail" != x""; then + if test x"${enable_strict_dependencies}" = x"yes"; then + as_fn_error $? "set --without-rlm_eap_tnc to disable it explicitly." "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_eap_tnc." >&5 +$as_echo "$as_me: WARNING: silently not building rlm_eap_tnc." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_eap_tnc requires: $fail." >&5 +$as_echo "$as_me: WARNING: FAILURE: rlm_eap_tnc requires: $fail." >&2;}; + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Required libraries are available from https://github.com/trustatfhh/tnc-fhh" >&5 +$as_echo "$as_me: WARNING: Required libraries are available from https://github.com/trustatfhh/tnc-fhh" >&2;}; + targetname="" + fi +fi + +mod_ldflags="$SMART_LIBS" +mod_cflags="$SMART_CPPFLAGS" + + + + + # keep this! Don't change! +ac_config_files="$ac_config_files all.mk" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + # keep this! Don't change! diff --git a/src/modules/rlm_eap/types/rlm_eap_tnc/configure.ac b/src/modules/rlm_eap/types/rlm_eap_tnc/configure.ac new file mode 100644 index 0000000..e5095eb --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_tnc/configure.ac @@ -0,0 +1,99 @@ +AC_PREREQ([2.68]) +AC_INIT(rlm_eap_tnc.c) +AC_REVISION($Revision$) +FR_INIT_MODULE([rlm_eap_tnc]) + +if test x$with_[]modname != xno; then + dnl extra argument: --with-eap-tnc-include-dir=DIR + eap_tnc_include_dir= + AC_ARG_WITH(eap-tnc-include-dir, + [AS_HELP_STRING([--with-eap-tnc-include-dir=DIR], + [Directory where the libtnc includes may be found])], + [case "$withval" in + no) + AC_MSG_ERROR(Need eap-tnc-include-dir) + ;; + yes) + ;; + *) + eap_tnc_include_dir="$withval" + ;; + esac]) + + dnl extra argument: --with-eap-tnc-lib-dir=DIR + eap_tnc_lib_dir= + AC_ARG_WITH(eap-tnc-lib-dir, + [AS_HELP_STRING([--with-eap-tnc-lib-dir=DIR], + [Directory where the libtnc libraries may be found])], + [case "$withval" in + no) + AC_MSG_ERROR(Need eap-tnc-lib-dir) + ;; + yes) + ;; + *) + eap_tnc_lib_dir="$withval" + ;; + esac]) + + dnl extra argument: --with-eap-tnc-dir=DIR + AC_ARG_WITH(eap-tnc-dir, + [AS_HELP_STRING([--with-eap-tnc-dir=DIR], + [Base directory where libtnc is installed])], + [case "$withval" in + no) + AC_MSG_ERROR(Need eap-tnc-dir) + ;; + yes) + ;; + *) + eap_tnc_lib_dir="$withval/lib" + eap_tnc_include_dir="$withval/include" + ;; + esac]) + + dnl ############################################################ + dnl # Check for eap-tnc includes + dnl ############################################################ + smart_try_dir="$eap_tnc_include_dir" + FR_SMART_CHECK_INCLUDE([naaeap/naaeap.h]) + if test "x$ac_cv_header_naaeap_naaeap_h" != "xyes"; then + fail="$fail naaeap.h" + fi + + dnl ############################################################ + dnl # Check for eap-tnc library + dnl ############################################################ + + smart_try_dir="$eap_tnc_lib_dir" + FR_SMART_CHECK_LIB([naaeap],[processEAPTNCData]) + if test "x$ac_cv_lib_naaeap_processEAPTNCData" != "xyes"; then + fail="$fail libnaaeap" + fi + + targetname=modname # keep this! Don't change! +else + targetname= # keep this! Don't change! + echo \*\*\* module modname is disabled. # keep this! Don't change! +fi + +dnl Don't change this section. +if test x"$fail" != x""; then + if test x"${enable_strict_dependencies}" = x"yes"; then + AC_MSG_ERROR([set --without-]modname[ to disable it explicitly.]) + else + AC_MSG_WARN([silently not building ]modname[.]) + AC_MSG_WARN([FAILURE: ]modname[ requires: $fail.]); + AC_MSG_WARN([Required libraries are available from https://github.com/trustatfhh/tnc-fhh]); + targetname="" + fi +fi + +mod_ldflags="$SMART_LIBS" +mod_cflags="$SMART_CPPFLAGS" + +AC_SUBST(mod_ldflags) +AC_SUBST(mod_cflags) + +AC_SUBST(targetname) # keep this! Don't change! +AC_OUTPUT(all.mk) # keep this! Don't change! diff --git a/src/modules/rlm_eap/types/rlm_eap_tnc/rlm_eap_tnc.c b/src/modules/rlm_eap/types/rlm_eap_tnc/rlm_eap_tnc.c new file mode 100644 index 0000000..a1fdbc0 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_tnc/rlm_eap_tnc.c @@ -0,0 +1,357 @@ +/* + * Portions of this code unrelated to FreeRADIUS are available + * separately under a commercial license. If you require an + * implementation of EAP-TNC that is not under the GPLv2, please + * contact trust@f4-i.fh-hannover.de for details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +/** + * $Id$ + * @file rlm_eap_tnc.c + * @brief Interfaces with the naeap library to provide EAP-TNC inner method. + * + * @copyright 2013 The FreeRADIUS project + * @copyright 2007 Alan DeKok <aland@deployingradius.com> + * @copyright 2006-2009 FH Hannover + */ + +/* + * EAP-TNC Packet with EAP Header, general structure + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Code | Identifier | Length | + * | | | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Flags | Ver | Data Length | + * | |L M S R R| =1 | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Data Length | Data ... + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <freeradius-devel/rad_assert.h> + +#include "eap.h" +#include <naaeap/naaeap.h> +#include <netinet/in.h> + +#define VERSION "0.7.0" +#define SET_START(x) ((x) | (0x20)) + +typedef struct rlm_eap_tnc { + char const *connection_string; +} rlm_eap_tnc_t; + +static CONF_PARSER module_config[] = { + { "connection_string", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_eap_tnc_t, connection_string), "NAS Port: %{NAS-Port} NAS IP: %{NAS-IP-Address} NAS_PORT_TYPE: %{NAS-Port-Type}" }, + CONF_PARSER_TERMINATOR +}; + +static int mod_instantiate(CONF_SECTION *cs, void **instance) +{ + rlm_eap_tnc_t *inst; + TNC_Result result; + + *instance = inst = talloc_zero(cs, rlm_eap_tnc_t); + if (!inst) return -1; + + /* + * Parse the configuration attributes. + */ + if (cf_section_parse(cs, inst, module_config) < 0) { + return -1; + } + + result = initializeDefault(); + if (result != TNC_RESULT_SUCCESS) { + ERROR("rlm_eap_tnc: NAA-EAP initializeDefault returned an " + "error code"); + + return -1; + } + + return 0; +} + +static int mod_detach(void *instance) +{ + TNC_Result result; + + talloc_free(instance); + + result = terminate(); + if (result != TNC_RESULT_SUCCESS) { + ERROR("rlm_eap_tnc: NAA-EAP terminate returned an " + "error code whilst detaching"); + return -1; + } + + return 0; +} + +/* + * This function is called when the first EAP_IDENTITY_RESPONSE message + * was received. + * + * Initiates the EPA_TNC session by sending the first EAP_TNC_RESPONSE + * to the peer. The packet has the Start-Bit set and contains no data. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Code | Identifier | Length | + * | | | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Flags | Ver | + * | |0 0 1 0 0|0 0 1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * For this package, only 'Identifier' has to be set dynamically. Any + * other information is static. + */ +static int mod_session_init(void *instance, eap_handler_t *handler) +{ + rlm_eap_tnc_t *inst = instance; + REQUEST *request = NULL; + + char buff[71]; + ssize_t len = 0; + + TNC_Result result; + TNC_ConnectionID conn_id; + + TNC_BufferReference eap_tnc_request; + TNC_BufferReference eap_tnc_user; + + VALUE_PAIR *username; + + /* + * Check if we run inside a secure EAP method. + * FIXME check concrete outer EAP method. + */ + if (!handler->request || !handler->request->parent) { + ERROR("rlm_eap_tnc: EAP_TNC must only be used as an " + "inner method within a protected tunneled EAP created " + "by an outer EAP method"); + + return 0; + } + + request = handler->request->parent; + + /* + * Build the connection string + */ + len = radius_xlat(buff, sizeof(buff), request, inst->connection_string, NULL, NULL); + if (len < 0){ + return 0; + } + + RDEBUG("Getting connection from NAA-EAP"); + + /* + * Get connection (uses a function from the NAA-EAP-library) + */ + result = getConnection(buff, &conn_id); + if (result != TNC_RESULT_SUCCESS) { + ERROR("rlm_eap_tnc: NAA-EAP getConnection returned an " + "error code"); + + return 0; + } + + /* + * Previous code manually parsed the EAP identity response + * this was wrong. rlm_eap will *always* create the Username + * from the EAP Identity response. + * + * Something has gone very wrong if the User-Name doesn't exist. + */ + username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY); + + RDEBUG("Username for TNC connection: %s", username->vp_strvalue); + + /* + * Stores the username associated with the connection + * + * What becomes of username? Who knows... but we don't free it + * so not safe to use talloc. + */ + MEM(eap_tnc_user = (TNC_BufferReference) strdup(username->vp_strvalue)); + + result = storeUsername(conn_id, eap_tnc_user, username->vp_length); + if (result != TNC_RESULT_SUCCESS) { + ERROR("rlm_eap_tnc: NAA-EAP storeUsername returned an " + "error code"); + + return 0; + } + + /* + * Set connection ID + */ + handler->opaque = talloc(handler, TNC_ConnectionID); + memcpy(handler->opaque, &conn_id, sizeof(TNC_ConnectionID)); + + /* + * Bild first EAP TNC request + */ + + MEM(eap_tnc_request = talloc_array(handler->eap_ds->request, uint8_t, 1)); + *eap_tnc_request = SET_START(1); + + handler->eap_ds->request->code = PW_EAP_REQUEST; + handler->eap_ds->request->type.num = PW_EAP_TNC; + + handler->eap_ds->request->type.length = 1; + + talloc_free(handler->eap_ds->request->type.data); + handler->eap_ds->request->type.data = eap_tnc_request; + + /* + * We don't need to authorize the user at this point. + * + * We also don't need to keep the challenge, as it's + * stored in 'handler->eap_ds', which will be given back + * to us... + */ + handler->stage = PROCESS; + + return 1; +} + +/** + * This function is called when a EAP_TNC_RESPONSE was received. + * It basically forwards the EAP_TNC data to NAA-TNCS and forms + * and appropriate EAP_RESPONSE. Furthermore, it sets the VlanID + * based on the TNC_ConnectionState determined by NAA-TNCS. + * + * @param instance The configuration data. + * @param handler The eap_handler_t. + * @return True, if successfully, else false. + */ +static int mod_process(UNUSED void *instance, eap_handler_t *handler) +{ + TNC_ConnectionID conn_id; + TNC_Result result; + + TNC_BufferReference data = NULL; + TNC_UInt32 datalen = 0; + + TNC_ConnectionState connection_state; + uint8_t code = 0; + REQUEST *request = handler->request; + + if (handler->eap_ds->response->type.num != PW_EAP_TNC) { + ERROR("rlm_eap_tnc: Incorrect response type"); + + return 0; + } + + /* + * Retrieve connection ID + */ + conn_id = *((TNC_ConnectionID *) (handler->opaque)); + + RDEBUG2("Starting authentication for connection ID %lX", + conn_id); + + /* + * Pass EAP_TNC data to NAA-EAP and get answer data + */ + connection_state = TNC_CONNECTION_STATE_CREATE; + + /* + * Forwards the eap_tnc data to NAA-EAP and gets the response + */ + result = processEAPTNCData(conn_id, handler->eap_ds->response->type.data, + handler->eap_ds->response->type.length, + &data, &datalen, &connection_state); + if (result != TNC_RESULT_SUCCESS) { + RDEBUG("NAA-EAP processEAPTNCData returned " + "an error code"); + + return 0; + } + /* + * Determine eap code for the response + */ + switch (connection_state) { + case TNC_CONNECTION_STATE_HANDSHAKE: + code = PW_EAP_REQUEST; + break; + + case TNC_CONNECTION_STATE_ACCESS_NONE: + code = PW_EAP_FAILURE; + pair_make_config("TNC-Status", "None", T_OP_SET); + break; + + case TNC_CONNECTION_STATE_ACCESS_ALLOWED: + code = PW_EAP_SUCCESS; + pair_make_config("TNC-Status", "Access", T_OP_SET); + break; + + case TNC_CONNECTION_STATE_ACCESS_ISOLATED: + code = PW_EAP_SUCCESS; + pair_make_config("TNC-Status", "Isolate", T_OP_SET); + break; + + default: + ERROR("rlm_eap_tnc: Invalid connection state"); + return 0; + } + + /* + * Build the TNC EAP request + */ + handler->eap_ds->request->code = code; + handler->eap_ds->request->type.num = PW_EAP_TNC; + + handler->eap_ds->request->type.length = datalen; + + talloc_free(handler->eap_ds->request->type.data); + + /* + * "data" is not talloc'd memory. + */ + handler->eap_ds->request->type.data = talloc_array(handler->eap_ds->request, + uint8_t, datalen); + memcpy(handler->eap_ds->request->type.data, data, datalen); + free(data); + + 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_tnc; +rlm_eap_module_t rlm_eap_tnc = { + .name = "eap_tnc", + .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 */ + .detach = mod_detach /* detach */ +}; diff --git a/src/modules/rlm_eap/types/rlm_eap_ttls/all.mk b/src/modules/rlm_eap/types/rlm_eap_ttls/all.mk new file mode 100644 index 0000000..2c7af7d --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_ttls/all.mk @@ -0,0 +1,10 @@ +TARGETNAME := rlm_eap_ttls + +ifneq "$(OPENSSL_LIBS)" "" +TARGET := $(TARGETNAME).a +endif + +SOURCES := $(TARGETNAME).c ttls.c + +SRC_INCDIRS := ../../ ../../libeap/ +TGT_PREREQS := libfreeradius-eap.a diff --git a/src/modules/rlm_eap/types/rlm_eap_ttls/eap_ttls.h b/src/modules/rlm_eap/types/rlm_eap_ttls/eap_ttls.h new file mode 100644 index 0000000..ff9a814 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_ttls/eap_ttls.h @@ -0,0 +1,46 @@ +/* + * eap_ttls.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_TTLS_H +#define _EAP_TTLS_H + +RCSIDH(eap_ttls_h, "$Id$") + +#include "eap_tls.h" + +typedef struct ttls_tunnel_t { + VALUE_PAIR *username; + VALUE_PAIR *state; + VALUE_PAIR *accept_vps; + bool authenticated; + int default_method; + bool copy_request_to_tunnel; + bool use_tunneled_reply; + char const *virtual_server; +} ttls_tunnel_t; + +/* + * Process the TTLS portion of an EAP-TTLS request. + */ +int eapttls_process(eap_handler_t *handler, tls_session_t *tls_session) CC_HINT(nonnull); + +#endif /* _EAP_TTLS_H */ diff --git a/src/modules/rlm_eap/types/rlm_eap_ttls/rlm_eap_ttls.c b/src/modules/rlm_eap/types/rlm_eap_ttls/rlm_eap_ttls.c new file mode 100644 index 0000000..4e53c92 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_ttls/rlm_eap_ttls.c @@ -0,0 +1,392 @@ +/* + * rlm_eap_ttls.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 2003 Alan DeKok <aland@freeradius.org> + * Copyright 2006 The FreeRADIUS server project + */ + +RCSID("$Id$") +USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ + +#include "eap_ttls.h" + +typedef struct rlm_eap_ttls_t { + /* + * TLS configuration + */ + char const *tls_conf_name; + fr_tls_server_conf_t *tls_conf; + + /* + * Default tunneled EAP type + */ + char const *default_method_name; + int default_method; + + /* + * Use the reply attributes from the tunneled session in + * the non-tunneled reply to the client. + */ + bool use_tunneled_reply; + + /* + * Use SOME of the request attributes from outside of the + * tunneled session in the tunneled request + */ + bool copy_request_to_tunnel; + + /* + * RFC 5281 (TTLS) says that the length field MUST NOT be + * in fragments after the first one. However, we've done + * it that way for years, and no one has complained. + * + * In the interests of allowing the server to follow the + * RFC, we add the option here. If set to "no", it sends + * the length field in ONLY the first fragment. + */ + bool include_length; + + /* + * Virtual server for inner tunnel session. + */ + char const *virtual_server; + + /* + * Do we do require a client cert? + */ + bool req_client_cert; +} rlm_eap_ttls_t; + + +static CONF_PARSER module_config[] = { + { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, tls_conf_name), NULL }, + { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, default_method_name), "md5" }, + { "copy_request_to_tunnel", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, copy_request_to_tunnel), "no" }, + { "use_tunneled_reply", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, use_tunneled_reply), "no" }, + { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, virtual_server), NULL }, + { "include_length", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, include_length), "yes" }, + { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, req_client_cert), "no" }, + CONF_PARSER_TERMINATOR +}; + + +/* + * Attach the module. + */ +static int mod_instantiate(CONF_SECTION *cs, void **instance) +{ + rlm_eap_ttls_t *inst; + + *instance = inst = talloc_zero(cs, rlm_eap_ttls_t); + if (!inst) return -1; + + /* + * Parse the configuration attributes. + */ + if (cf_section_parse(cs, inst, module_config) < 0) { + 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. + */ + inst->default_method = eap_name2type(inst->default_method_name); + if (inst->default_method < 0) { + ERROR("rlm_eap_ttls: 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_ttls: Failed initializing SSL context"); + return -1; + } + + return 0; +} + +/* + * Allocate the TTLS per-session data + */ +static ttls_tunnel_t *ttls_alloc(TALLOC_CTX *ctx, rlm_eap_ttls_t *inst) +{ + ttls_tunnel_t *t; + + t = talloc_zero(ctx, ttls_tunnel_t); + + 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->virtual_server = inst->virtual_server; + return t; +} + + +/* + * 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 status; + tls_session_t *ssn; + rlm_eap_ttls_t *inst; + VALUE_PAIR *vp; + bool client_cert; + REQUEST *request = handler->request; + + inst = type_arg; + + handler->tls = true; + + /* + * Check if we need a client certificate. + */ + + /* + * 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; + } + + /* + * Allow TLS 1.3, it works. + */ + ssn = eaptls_session(handler, inst->tls_conf, client_cert, true); + if (!ssn) { + return 0; + } + + handler->opaque = ((void *)ssn); + + /* + * Set the label to a fixed string. For TLS 1.3, the + * label is the same for all TLS-based EAP methods. If + * the client is using TLS 1.3, then eaptls_success() + * will over-ride this label with the correct label for + * TLS 1.3. + */ + ssn->label = "ttls keying material"; + + /* + * TLS session initialization is over. Now handle TLS + * related handshaking or application data. + */ + status = eaptls_start(handler->eap_ds, ssn->peap_flag); + if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) { + REDEBUG("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } else { + RDEBUG3("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } + if (status == 0) return 0; + + /* + * The next stage to process the packet. + */ + handler->stage = PROCESS; + + 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; + int ret = 0; + fr_tls_status_t status; + rlm_eap_ttls_t *inst = (rlm_eap_ttls_t *) arg; + tls_session_t *tls_session = (tls_session_t *) handler->opaque; + ttls_tunnel_t *t = (ttls_tunnel_t *) tls_session->opaque; + REQUEST *request = handler->request; + + RDEBUG2("Authenticate"); + + tls_session->length_flag = inst->include_length; + + /* + * 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 { + RDEBUG3("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } + + /* + * Make request available to any SSL callbacks + */ + SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, request); + 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: + if (SSL_session_reused(tls_session->ssl)) { + RDEBUG("Skipping Phase2 due to session resumption"); + goto do_keys; + } + + if (t && t->authenticated) { + 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"); + } + + do_keys: + /* + * Success: Automatically return MPPE keys. + */ + ret = eaptls_success(handler, 0); + goto done; + } else { + eaptls_request(handler->eap_ds, tls_session); + } + ret = 1; + goto done; + + /* + * The TLS code is still working on the TLS + * exchange, and it's a valid TLS request. + * do nothing. + */ + case FR_TLS_HANDLED: + ret = 1; + goto done; + + /* + * Handshake is done, proceed with decoding tunneled + * data. + */ + case FR_TLS_OK: + break; + + /* + * Anything else: fail. + */ + default: + ret = 0; + goto done; + } + + /* + * Session is established, proceed with decoding + * tunneled data. + */ + RDEBUG2("Session established. Proceeding to decode tunneled attributes"); + + /* + * We may need TTLS data associated with the session, so + * allocate it here, if it wasn't already alloacted. + */ + if (!tls_session->opaque) { + tls_session->opaque = ttls_alloc(tls_session, inst); + } + + /* + * Process the TTLS portion of the request. + */ + rcode = eapttls_process(handler, tls_session); + switch (rcode) { + case PW_CODE_ACCESS_REJECT: + eaptls_fail(handler, 0); + ret = 0; + goto done; + + /* + * Access-Challenge, continue tunneled conversation. + */ + case PW_CODE_ACCESS_CHALLENGE: + eaptls_request(handler->eap_ds, tls_session); + ret = 1; + goto done; + + /* + * Success: Automatically return MPPE keys. + */ + case PW_CODE_ACCESS_ACCEPT: + goto do_keys; + + /* + * 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 + ret = 1; + goto done; + + default: + break; + } + + /* + * Something we don't understand: Reject it. + */ + eaptls_fail(handler, 0); + +done: + SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, NULL); + + return ret; +} + +/* + * The module name should be the only globally exported symbol. + * That is, everything else should be 'static'. + */ +extern rlm_eap_module_t rlm_eap_ttls; +rlm_eap_module_t rlm_eap_ttls = { + .name = "eap_ttls", + .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 */ +}; diff --git a/src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c b/src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c new file mode 100644 index 0000000..cbe4239 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c @@ -0,0 +1,1321 @@ +/* + * rlm_eap_ttls.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 2003 Alan DeKok <aland@freeradius.org> + * Copyright 2006 The FreeRADIUS server project + */ + +RCSID("$Id$") + +#include "eap_ttls.h" +#include "eap_chbind.h" + +/* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | AVP Code | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |V M r r r r r r| AVP Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Vendor-ID (opt) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Data ... + * +-+-+-+-+-+-+-+-+ + */ + +/* + * Verify that the diameter packet is valid. + */ +static int diameter_verify(REQUEST *request, uint8_t const *data, unsigned int data_len) +{ + uint32_t attr; + uint32_t length; + unsigned int hdr_len; + unsigned int remaining = data_len; + + while (remaining > 0) { + hdr_len = 12; + + if (remaining < hdr_len) { + RDEBUG2("Diameter attribute is too small (%u) to contain a Diameter header", remaining); + return 0; + } + + memcpy(&attr, data, sizeof(attr)); + attr = ntohl(attr); + memcpy(&length, data + 4, sizeof(length)); + length = ntohl(length); + + if ((data[4] & 0x80) != 0) { + if (remaining < 16) { + RDEBUG2("Diameter attribute is too small to contain a Diameter header with Vendor-Id"); + return 0; + } + + hdr_len = 16; + } + + /* + * Get the length. If it's too big, die. + */ + length &= 0x00ffffff; + + /* + * Too short or too long is bad. + */ + if (length <= (hdr_len - 4)) { + RDEBUG2("Tunneled attribute %u is too short (%u < %u) to contain anything useful.", attr, + length, hdr_len); + return 0; + } + + if (length > remaining) { + RDEBUG2("Tunneled attribute %u is longer than room remaining in the packet (%u > %u).", attr, + length, remaining); + return 0; + } + + /* + * Check for broken implementations, which don't + * pad the AVP to a 4-octet boundary. + */ + if (remaining == length) break; + + /* + * The length does NOT include the padding, so + * we've got to account for it here by rounding up + * to the nearest 4-byte boundary. + */ + length += 0x03; + length &= ~0x03; + + /* + * If the rest of the diameter packet is larger than + * this attribute, continue. + * + * Otherwise, if the attribute over-flows the end + * of the packet, die. + */ + if (remaining < length) { + REDEBUG2("Diameter attribute overflows packet!"); + return 0; + } + + /* + * remaining > length, continue. + */ + remaining -= length; + data += length; + } + + /* + * We got this far. It looks OK. + */ + return 1; +} + + +/* + * Convert diameter attributes to our VALUE_PAIR's + */ +static VALUE_PAIR *diameter2vp(REQUEST *request, REQUEST *fake, SSL *ssl, + uint8_t const *data, size_t data_len) +{ + uint32_t attr; + uint32_t vendor; + uint32_t length; + size_t offset; + size_t size; + size_t data_left = data_len; + VALUE_PAIR *first = NULL; + VALUE_PAIR *vp = NULL; + RADIUS_PACKET *packet = fake->packet; /* FIXME: api issues */ + vp_cursor_t out; + DICT_ATTR const *da; + + fr_cursor_init(&out, &first); + + /* + * Parse while there's still data. + */ + while (data_left >= 9) { + size_t attr_len; + + rad_assert(data_left <= data_len); + memcpy(&attr, data, sizeof(attr)); + data += 4; + attr = ntohl(attr); + vendor = 0; + + memcpy(&length, data, sizeof(length)); + data += 4; + length = ntohl(length); + + /* + * Length is *value* length. The actual + * attributes are aligned on 4 octets. + */ + attr_len = length & 0x00ffffff; + attr_len += 0x03; + attr_len &= ~(uint32_t) 0x03; + + /* + * A "vendor" flag, with a vendor ID of zero, + * is equivalent to no vendor. This is stupid. + */ + offset = 8; + if ((length & ((uint32_t)1 << 31)) != 0) { + memcpy(&vendor, data, sizeof(vendor)); + vendor = ntohl(vendor); + + data += 4; /* skip the vendor field, it's zero */ + offset += 4; /* offset to value field */ + + if (attr > 65535) { + DEBUG("Skipping Diameter attribute %08x", attr); + goto next_attr; + } + if (vendor > FR_MAX_VENDOR) { + DEBUG("Skipping large vendor ID %08x", vendor); + goto next_attr; + } + } + + /* + * FIXME: Handle the M bit. For now, we assume that + * some other module takes care of any attribute + * with the M bit set. + */ + + /* + * Get the length. + */ + length &= 0x00ffffff; + + /* + * Get the size of the value portion of the + * attribute. + */ + size = length - offset; + + /* + * Vendor attributes can be larger than 255. + * Normal attributes cannot be. + */ + if ((attr > 255) && (vendor == 0)) { + RWDEBUG2("Skipping Diameter attribute %u", attr); + goto next_attr; + } + + /* + * EAP-Message AVPs can be larger than 253 octets. + * + * For now, we rely on the main decoder in + * src/lib/radius to decode data into VPs. This + * means putting the data into a RADIUS attribute + * format. It also means that we can't handle + * "extended" attributes in the Diameter space. Oh well... + */ + if ((size > 253) && !((vendor == 0) && (attr == PW_EAP_MESSAGE))) { + RWDEBUG2("diameter2vp skipping long attribute %u", attr); + goto next_attr; + } + + /* + * RADIUS VSAs are handled as Diameter attributes + * with Vendor-Id == 0, and the VSA data packed + * into the "String" field as per normal. + * + * EXCEPT for the MS-CHAP attributes. + */ + if ((vendor == 0) && (attr == PW_VENDOR_SPECIFIC)) { + ssize_t decoded; + uint8_t buffer[256]; + + buffer[0] = PW_VENDOR_SPECIFIC; + buffer[1] = size + 2; + memcpy(buffer + 2, data, size); + + vp = NULL; + decoded = rad_attr2vp(packet, NULL, NULL, NULL, + buffer, size + 2, &vp); + if (decoded < 0) { + REDEBUG2("diameter2vp failed decoding attr: %s", + fr_strerror()); + goto raw; + } + + if ((size_t) decoded != size + 2) { + REDEBUG2("diameter2vp failed to entirely decode VSA"); + fr_pair_list_free(&vp); + goto raw; + } + + fr_cursor_merge(&out, vp); + + goto next_attr; + } + + /* + * Create it. If this fails, it's because we're OOM. + */ + da = dict_attrbyvalue(attr, vendor); + if (!da) goto raw; + + vp = fr_pair_afrom_da(packet, da); + if (!vp) { + RDEBUG2("Failure in creating VP"); + fr_pair_list_free(&first); + return NULL; + } + + /* + * If it's a type from our dictionary, then + * we need to put the data in a relevant place. + * + * @todo: Export the lib/radius.c decoder, and use it here! + */ + switch (vp->da->type) { + case PW_TYPE_INTEGER: + case PW_TYPE_DATE: + if (size != vp->vp_length) { + /* + * Bad format. Create a "raw" + * attribute. + */ + raw: + if (vp) fr_pair_list_free(&vp); + da = dict_unknown_afrom_fields(packet, attr, vendor); + if (!da) return NULL; + vp = fr_pair_afrom_da(packet, da); + if (!vp) return NULL; + fr_pair_value_memcpy(vp, data, size); + break; + } + memcpy(&vp->vp_integer, data, vp->vp_length); + + /* + * Stored in host byte order: change it. + */ + vp->vp_integer = ntohl(vp->vp_integer); + break; + + case PW_TYPE_INTEGER64: + if (size != vp->vp_length) goto raw; + memcpy(&vp->vp_integer64, data, vp->vp_length); + + /* + * Stored in host byte order: change it. + */ + vp->vp_integer64 = ntohll(vp->vp_integer64); + break; + + case PW_TYPE_IPV4_ADDR: + if (size != vp->vp_length) { + RDEBUG2("Invalid length attribute %d", + attr); + fr_pair_list_free(&first); + fr_pair_list_free(&vp); + return NULL; + } + memcpy(&vp->vp_ipaddr, data, vp->vp_length); + + /* + * Stored in network byte order: don't change it. + */ + break; + + case PW_TYPE_BYTE: + if (size != vp->vp_length) goto raw; + vp->vp_byte = data[0]; + break; + + case PW_TYPE_SHORT: + if (size != vp->vp_length) goto raw; + vp->vp_short = (data[0] * 256) + data[1]; + break; + + case PW_TYPE_SIGNED: + if (size != vp->vp_length) goto raw; + memcpy(&vp->vp_signed, data, vp->vp_length); + vp->vp_signed = ntohl(vp->vp_signed); + break; + + case PW_TYPE_IPV6_ADDR: + if (size != vp->vp_length) goto raw; + memcpy(&vp->vp_ipv6addr, data, vp->vp_length); + break; + + case PW_TYPE_IPV6_PREFIX: + if (size != vp->vp_length) goto raw; + memcpy(vp->vp_ipv6prefix, data, vp->vp_length); + break; + + case PW_TYPE_STRING: + fr_pair_value_bstrncpy(vp, data, size); + vp->vp_length = strlen(vp->vp_strvalue); /* embedded zeros are NOT allowed */ + break; + + /* + * Copy it over verbatim. + */ + case PW_TYPE_OCTETS: + default: + fr_pair_value_memcpy(vp, data, size); + break; + } + + /* + * Ensure that the client is using the + * correct challenge. This weirdness is + * to protect against against replay + * attacks, where anyone observing the + * CHAP exchange could pose as that user, + * by simply choosing to use the same + * challenge. + * + * By using a challenge based on + * information from the current session, + * we can guarantee that the client is + * not *choosing* a challenge. + * + * We're a little forgiving in that we + * have loose checks on the length, and + * we do NOT check the Id (first octet of + * the response to the challenge) + * + * But if the client gets the challenge correct, + * we're not too worried about the Id. + */ + if (((vp->da->vendor == 0) && (vp->da->attr == PW_CHAP_CHALLENGE)) || + ((vp->da->vendor == VENDORPEC_MICROSOFT) && (vp->da->attr == PW_MSCHAP_CHALLENGE))) { + uint8_t challenge[17]; + + if ((vp->vp_length < 8) || + (vp->vp_length > 16)) { + RDEBUG("Tunneled challenge has invalid length"); + fr_pair_list_free(&first); + fr_pair_list_free(&vp); + return NULL; + } + + /* + * TLSv1.3 exports a different key depending on the length + * requested so ask for *exactly* what the spec requires + */ + eapttls_gen_challenge(ssl, challenge, vp->vp_length + 1); + + if (memcmp(challenge, vp->vp_octets, + vp->vp_length) != 0) { + RDEBUG("Tunneled challenge is incorrect"); + fr_pair_list_free(&first); + fr_pair_list_free(&vp); + return NULL; + } + } + + /* + * Update the list. + */ + fr_cursor_insert(&out, vp); + + next_attr: + if (data_left <= attr_len) break; + + data_left -= attr_len; + data += (attr_len - offset); + } + + /* + * We got this far. It looks OK. + */ + return first; +} + +/* + * Convert VALUE_PAIR's to diameter attributes, and write them + * to an SSL session. + * + * The ONLY VALUE_PAIR's which may be passed to this function + * are ones which can go inside of a RADIUS (i.e. diameter) + * packet. So no server-configuration attributes, or the like. + */ +static int vp2diameter(REQUEST *request, tls_session_t *tls_session, VALUE_PAIR *first) +{ + /* + * RADIUS packets are no more than 4k in size, so if + * we've got more than 4k of data to write, it's very + * bad. + */ + uint8_t buffer[4096]; + uint8_t *p; + uint32_t attr; + uint32_t length; + uint32_t vendor; + size_t total; + uint64_t attr64; + VALUE_PAIR *vp; + vp_cursor_t cursor; + + p = buffer; + total = 0; + + for (vp = fr_cursor_init(&cursor, &first); vp; vp = fr_cursor_next(&cursor)) { + /* + * Too much data: die. + */ + if ((total + vp->vp_length + 12) >= sizeof(buffer)) { + RDEBUG2("output buffer is full!"); + return 0; + } + + /* + * Hmm... we don't group multiple EAP-Messages + * together. Maybe we should... + */ + + length = vp->vp_length; + vendor = vp->da->vendor; + if (vendor != 0) { + attr = vp->da->attr & 0xffff; + length |= ((uint32_t)1 << 31); + } else { + attr = vp->da->attr; + } + + /* + * Hmm... set the M bit for all attributes? + */ + length |= (1 << 30); + + attr = ntohl(attr); + + memcpy(p, &attr, sizeof(attr)); + p += 4; + total += 4; + + length += 8; /* includes 8 bytes of attr & length */ + + if (vendor != 0) { + length += 4; /* include 4 bytes of vendor */ + + length = ntohl(length); + memcpy(p, &length, sizeof(length)); + p += 4; + total += 4; + + vendor = ntohl(vendor); + memcpy(p, &vendor, sizeof(vendor)); + p += 4; + total += 4; + } else { + length = ntohl(length); + memcpy(p, &length, sizeof(length)); + p += 4; + total += 4; + } + + switch (vp->da->type) { + case PW_TYPE_INTEGER: + case PW_TYPE_DATE: + attr = htonl(vp->vp_integer); /* stored in host order */ + memcpy(p, &attr, sizeof(attr)); + length = 4; + break; + + case PW_TYPE_INTEGER64: + attr64 = htonll(vp->vp_integer64); /* stored in host order */ + memcpy(p, &attr64, sizeof(attr64)); + length = 8; + break; + + case PW_TYPE_IPV4_ADDR: + memcpy(p, &vp->vp_ipaddr, 4); /* network order */ + length = 4; + break; + + case PW_TYPE_STRING: + case PW_TYPE_OCTETS: + default: + memcpy(p, vp->vp_strvalue, vp->vp_length); + length = vp->vp_length; + break; + } + + /* + * Skip to the end of the data. + */ + p += length; + total += length; + + /* + * Align the data to a multiple of 4 bytes. + */ + if ((total & 0x03) != 0) { + size_t i; + + length = 4 - (total & 0x03); + for (i = 0; i < length; i++) { + *p = '\0'; + p++; + total++; + } + } + } /* loop over the VP's to write. */ + + /* + * Write the data in the buffer to the SSL session. + */ + if (total > 0) { +#ifndef NDEBUG + size_t i; + + if ((rad_debug_lvl > 2) && fr_log_fp) { + for (i = 0; i < total; i++) { + if ((i & 0x0f) == 0) fprintf(fr_log_fp, " TTLS tunnel data out %04x: ", (int) i); + + fprintf(fr_log_fp, "%02x ", buffer[i]); + + if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n"); + } + if ((total & 0x0f) != 0) fprintf(fr_log_fp, "\n"); + } +#endif + + (tls_session->record_plus)(&tls_session->clean_in, buffer, total); + + /* + * FIXME: Check the return code. + */ + tls_handshake_send(request, tls_session); + } + + /* + * Everything's OK. + */ + return 1; +} + +/* + * Use a reply packet to determine what to do. + */ +static rlm_rcode_t CC_HINT(nonnull) process_reply(eap_handler_t *handler, tls_session_t *tls_session, + REQUEST *request, RADIUS_PACKET *reply) +{ + rlm_rcode_t rcode = RLM_MODULE_REJECT; + VALUE_PAIR *vp; + ttls_tunnel_t *t = tls_session->opaque; + + rad_assert(handler->request == request); + + /* + * If the response packet was Access-Accept, then + * we're OK. If not, die horribly. + * + * FIXME: Take MS-CHAP2-Success attribute, and + * tunnel it back to the client, to authenticate + * ourselves to the client. + * + * FIXME: If we have an Access-Challenge, then + * the Reply-Message is tunneled back to the client. + * + * FIXME: If we have an EAP-Message, then that message + * must be tunneled back to the client. + * + * FIXME: If we have an Access-Challenge with a State + * attribute, then do we tunnel that to the client, or + * keep track of it ourselves? + * + * 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: + tls_session->authentication_success = true; + RDEBUG("Got tunneled Access-Accept"); + + rcode = RLM_MODULE_OK; + + /* + * Always delete MPPE keys & encryption policy + * from the tunneled reply. These never get sent + * back to the user. + */ + 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); + + /* + * MS-CHAP2-Success means that we do NOT return + * an Access-Accept, but instead tunnel that + * attribute to the client, and keep going with + * the TTLS session. Once the client accepts + * our identity, it will respond with an empty + * packet, and we will send EAP-Success. + */ + vp = NULL; + fr_pair_list_mcopy_by_num(tls_session, &vp, &reply->vps, PW_MSCHAP2_SUCCESS, VENDORPEC_MICROSOFT, TAG_ANY); + if (vp) { + RDEBUG("Got MS-CHAP2-Success, tunneling it to the client in a challenge"); + rcode = RLM_MODULE_HANDLED; + t->authenticated = true; + + /* + * Use the tunneled reply, but not now. + */ + if (t->use_tunneled_reply) { + rad_assert(!t->accept_vps); + fr_pair_list_mcopy_by_num(t, &t->accept_vps, &reply->vps, + 0, 0, TAG_ANY); + rad_assert(!reply->vps); + } + + } else { /* no MS-CHAP2-Success */ + /* + * Can only have EAP-Message if there's + * no MS-CHAP2-Success. + * + * We also do NOT tunnel the EAP-Success + * attribute back to the client, as the client + * can figure it out, from the non-tunneled + * EAP-Success packet. + */ + fr_pair_list_mcopy_by_num(tls_session, &vp, &reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY); + fr_pair_list_free(&vp); + } + + /* move channel binding responses; we need to send them */ + fr_pair_list_mcopy_by_num(tls_session, &vp, &reply->vps, PW_UKERNA_CHBIND, VENDORPEC_UKERNA, TAG_ANY); + if (fr_pair_find_by_num(vp, PW_UKERNA_CHBIND, VENDORPEC_UKERNA, TAG_ANY) != NULL) { + t->authenticated = true; + /* + * Use the tunneled reply, but not now. + */ + if (t->use_tunneled_reply) { + rad_assert(!t->accept_vps); + fr_pair_list_mcopy_by_num(t, &t->accept_vps, &reply->vps, + 0, 0, TAG_ANY); + rad_assert(!reply->vps); + } + rcode = RLM_MODULE_HANDLED; + } + + /* + * Handle the ACK, by tunneling any necessary reply + * VP's back to the client. + */ + if (vp) { + RDEBUG("Sending tunneled reply attributes"); + rdebug_pair_list(L_DBG_LVL_1, request, vp, NULL); + + vp2diameter(request, tls_session, vp); + fr_pair_list_free(&vp); + } + + /* + * If we've been told to use the attributes from + * the reply, then do so. + * + * WARNING: This may leak information about the + * tunneled user! + */ + if (t->use_tunneled_reply) { + fr_pair_delete_by_num(&reply->vps, PW_PROXY_STATE, 0, TAG_ANY); + fr_pair_list_mcopy_by_num(request->reply, &request->reply->vps, + &reply->vps, 0, 0, TAG_ANY); + } + 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); + + /* + * We should really be a bit smarter about this, + * and move over only those attributes which + * are relevant to the authentication request, + * but that's a lot more work, and this "dumb" + * method works in 99.9% of the situations. + */ + vp = NULL; + fr_pair_list_mcopy_by_num(t, &vp, &reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY); + + /* + * There MUST be a Reply-Message in the challenge, + * which we tunnel back to the client. + * + * If there isn't one in the reply VP's, then + * we MUST create one, with an empty string as + * it's value. + */ + fr_pair_list_mcopy_by_num(t, &vp, &reply->vps, PW_REPLY_MESSAGE, 0, TAG_ANY); + + /* also move chbind messages, if any */ + fr_pair_list_mcopy_by_num(t, &vp, &reply->vps, PW_UKERNA_CHBIND, VENDORPEC_UKERNA, + TAG_ANY); + + /* + * Handle the ACK, by tunneling any necessary reply + * VP's back to the client. + */ + if (vp) { + vp2diameter(request, tls_session, vp); + fr_pair_list_free(&vp); + } + rcode = RLM_MODULE_HANDLED; + break; + + default: + RDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code); + rcode = RLM_MODULE_INVALID; + break; + } + + return rcode; +} + + +#ifdef WITH_PROXY +/* + * Do post-proxy processing, + */ +static int CC_HINT(nonnull) eapttls_postproxy(eap_handler_t *handler, void *data) +{ + int rcode; + tls_session_t *tls_session = (tls_session_t *) data; + REQUEST *fake, *request = handler->request; + + RDEBUG("Passing reply from proxy back into the tunnel"); + + /* + * If there was a fake request associated with the proxied + * request, do more processing of it. + */ + fake = (REQUEST *) request_data_get(handler->request, + handler->request->proxy, + REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK); + + /* + * Do the callback, if it exists, and if it was a success. + */ + if (fake && (handler->request->proxy_reply->code == PW_CODE_ACCESS_ACCEPT)) { + /* + * Terrible hacks. + */ + rad_assert(!fake->packet); + fake->packet = talloc_steal(fake, request->proxy); + fake->packet->src_ipaddr = request->packet->src_ipaddr; + request->proxy = NULL; + + rad_assert(!fake->reply); + fake->reply = talloc_steal(fake, request->proxy_reply); + request->proxy_reply = NULL; + + if ((rad_debug_lvl > 0) && fr_log_fp) { + fprintf(fr_log_fp, "server %s {\n", + (!fake->server) ? "" : fake->server); + } + + /* + * Perform a post-auth stage for the tunneled + * session. + */ + fake->options &= ~RAD_REQUEST_OPTION_PROXY_EAP; + rcode = rad_postauth(fake); + RDEBUG2("post-auth returns %d", rcode); + + if ((rad_debug_lvl > 0) && fr_log_fp) { + fprintf(fr_log_fp, "} # server %s\n", + (!fake->server) ? "" : fake->server); + + RDEBUG("Final reply from tunneled session code %d", fake->reply->code); + rdebug_pair_list(L_DBG_LVL_1, request, fake->reply->vps, NULL); + } + + /* + * Terrible hacks. + */ + request->proxy = talloc_steal(request, fake->packet); + fake->packet = NULL; + request->proxy_reply = talloc_steal(request, fake->reply); + fake->reply = NULL; + + /* + * And we're done with this request. + */ + + switch (rcode) { + case RLM_MODULE_FAIL: + talloc_free(fake); + eaptls_fail(handler, 0); + return 0; + + default: /* Don't Do Anything */ + RDEBUG2("Got reply %d", + request->proxy_reply->code); + break; + } + } + talloc_free(fake); /* robust if !fake */ + + /* + * Process the reply from the home server. + */ + rcode = process_reply(handler, tls_session, handler->request, handler->request->proxy_reply); + + /* + * The proxy code uses the reply from the home server as + * the basis for the reply to the NAS. We don't want that, + * so we toss it, after we've had our way with it. + */ + fr_pair_list_free(&handler->request->proxy_reply->vps); + + switch (rcode) { + case RLM_MODULE_REJECT: + RDEBUG("Reply was rejected"); + break; + + case RLM_MODULE_HANDLED: + RDEBUG("Reply was handled"); + eaptls_request(handler->eap_ds, tls_session); + request->proxy_reply->code = PW_CODE_ACCESS_CHALLENGE; + return 1; + + case RLM_MODULE_OK: + RDEBUG("Reply was OK"); + + /* + * Success: Automatically return MPPE keys. + */ + return eaptls_success(handler, 0); + + default: + RDEBUG("Reply was unknown"); + break; + } + + eaptls_fail(handler, 0); + return 0; +} + +#endif /* WITH_PROXY */ + +/* + * Process the "diameter" contents of the tunneled data. + */ +int eapttls_process(eap_handler_t *handler, tls_session_t *tls_session) +{ + PW_CODE code = PW_CODE_ACCESS_REJECT; + rlm_rcode_t rcode; + REQUEST *fake; + VALUE_PAIR *vp; + ttls_tunnel_t *t; + uint8_t const *data; + size_t data_len; + REQUEST *request = handler->request; + chbind_packet_t *chbind; + + /* + * Just look at the buffer directly, without doing + * record_minus. + */ + data_len = tls_session->clean_out.used; + tls_session->clean_out.used = 0; + data = tls_session->clean_out.data; + + t = (ttls_tunnel_t *) tls_session->opaque; + + /* + * If there's no data, maybe this is an ACK to an + * MS-CHAP2-Success. + */ + if (data_len == 0) { + if (t->authenticated) { + RDEBUG("Got ACK, and the user was already authenticated"); + return PW_CODE_ACCESS_ACCEPT; + } /* else no session, no data, die. */ + + /* + * FIXME: Call SSL_get_error() to see what went + * wrong. + */ + RDEBUG2("SSL_read Error"); + return PW_CODE_ACCESS_REJECT; + } + +#ifndef NDEBUG + if ((rad_debug_lvl > 2) && fr_log_fp) { + size_t i; + + for (i = 0; i < data_len; i++) { + if ((i & 0x0f) == 0) fprintf(fr_log_fp, " TTLS tunnel data in %04x: ", (int) i); + + fprintf(fr_log_fp, "%02x ", data[i]); + + if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n"); + } + if ((data_len & 0x0f) != 0) fprintf(fr_log_fp, "\n"); + } +#endif + + if (!diameter_verify(request, data, data_len)) { + return PW_CODE_ACCESS_REJECT; + } + + /* + * Allocate a fake REQUEST structure. + */ + fake = request_alloc_fake(request); + + rad_assert(!fake->packet->vps); + + /* + * Add the tunneled attributes to the fake request. + */ + fake->packet->vps = diameter2vp(request, fake, tls_session->ssl, data, data_len); + if (!fake->packet->vps) { + talloc_free(fake); + return PW_CODE_ACCESS_REJECT; + } + + /* + * 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); + + RDEBUG("Got tunneled request"); + rdebug_pair_list(L_DBG_LVL_1, request, fake->packet->vps, NULL); + + /* + * 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); + + /* + * If there's a default EAP type, + * set it here. + */ + if (t->default_method != 0) { + RDEBUG("Setting default EAP type for tunneled EAP session"); + vp = fr_pair_afrom_num(fake, PW_EAP_TYPE, 0); + rad_assert(vp != NULL); + vp->vp_integer = t->default_method; + fr_pair_add(&fake->config, vp); + } + + } 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 = fr_pair_find_by_num(fake->packet->vps, PW_USER_NAME, 0, TAG_ANY); + } + } /* 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 this is set, we copy SOME of the request attributes + * from outside of the tunnel to inside of the tunnel. + * + * We copy ONLY those attributes which do NOT already + * exist in the tunneled request. + */ + if (t->copy_request_to_tunnel) { + VALUE_PAIR *copy; + 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->vendor == 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); + } + } + + 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 */ + + + if ((rad_debug_lvl > 0) && fr_log_fp) { + RDEBUG("Sending tunneled request"); + } + + /* + * Process channel binding. + */ + chbind = eap_chbind_vp2packet(fake, fake->packet->vps); + if (chbind) { + PW_CODE chbind_code; + CHBIND_REQ *req = talloc_zero(fake, CHBIND_REQ); + + RDEBUG("received chbind request"); + req->request = chbind; + if (fake->username) { + req->username = fake->username; + } else { + req->username = NULL; + } + chbind_code = chbind_process(request, req); + + /* encapsulate response here */ + if (req->response) { + RDEBUG("sending chbind response"); + fr_pair_add(&fake->reply->vps, + eap_chbind_packet2vp(fake->reply, req->response)); + } else { + RDEBUG("no chbind response"); + } + + /* clean up chbind req */ + talloc_free(req); + + if (chbind_code != PW_CODE_ACCESS_ACCEPT) { + return chbind_code; + } + } + + /* + * 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: /* No reply code, must be proxied... */ +#ifdef WITH_PROXY + vp = fr_pair_find_by_num(fake->config, PW_PROXY_TO_REALM, 0, TAG_ANY); + if (vp) { + eap_tunnel_data_t *tunnel; + RDEBUG("Tunneled authentication will be proxied to %s", vp->vp_strvalue); + + /* + * Tell the original request that it's going + * to be proxied. + */ + fr_pair_list_mcopy_by_num(request, &request->config, + &fake->config, + PW_PROXY_TO_REALM, 0, TAG_ANY); + + /* + * Seed the proxy packet with the + * tunneled request. + */ + rad_assert(!request->proxy); + request->proxy = talloc_steal(request, fake->packet); + memset(&request->proxy->src_ipaddr, 0, + sizeof(request->proxy->src_ipaddr)); + memset(&request->proxy->src_ipaddr, 0, + sizeof(request->proxy->src_ipaddr)); + request->proxy->src_port = 0; + request->proxy->dst_port = 0; + fake->packet = NULL; + rad_free(&fake->reply); + fake->reply = NULL; + + /* + * Set up the callbacks for the tunnel + */ + tunnel = talloc_zero(request, eap_tunnel_data_t); + tunnel->tls_session = tls_session; + tunnel->callback = eapttls_postproxy; + + /* + * Associate the callback with the request. + */ + code = request_data_add(request, request->proxy, REQUEST_DATA_EAP_TUNNEL_CALLBACK, + tunnel, false); + rad_assert(code == 0); + + /* + * rlm_eap.c has taken care of associating + * the handler with the fake request. + * + * So we associate the fake request with + * this request. + */ + code = request_data_add(request, request->proxy, REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK, + fake, true); + rad_assert(code == 0); + fake = NULL; + + /* + * Didn't authenticate the packet, but + * we're proxying it. + */ + code = PW_CODE_STATUS_CLIENT; + + } else +#endif /* WITH_PROXY */ + { + RDEBUG("No tunneled reply was found for request %d , and the request was not proxied: rejecting the user.", + request->number); + code = PW_CODE_ACCESS_REJECT; + } + break; + + default: + /* + * Returns RLM_MODULE_FOO, and we want to return PW_FOO + */ + rcode = process_reply(handler, 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; +} |