summaryrefslogtreecommitdiffstats
path: root/src/modules/rlm_rest
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/modules/rlm_rest/.gitignore1
-rw-r--r--src/modules/rlm_rest/all.mk.in14
-rw-r--r--src/modules/rlm_rest/config.h.in85
-rwxr-xr-xsrc/modules/rlm_rest/configure5255
-rw-r--r--src/modules/rlm_rest/configure.ac173
-rwxr-xr-xsrc/modules/rlm_rest/demo.pl59
-rw-r--r--src/modules/rlm_rest/rest.c2682
-rw-r--r--src/modules/rlm_rest/rest.h323
-rw-r--r--src/modules/rlm_rest/rlm_rest.c1003
9 files changed, 9595 insertions, 0 deletions
diff --git a/src/modules/rlm_rest/.gitignore b/src/modules/rlm_rest/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_rest/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_rest/all.mk.in b/src/modules/rlm_rest/all.mk.in
new file mode 100644
index 0000000..89f0390
--- /dev/null
+++ b/src/modules/rlm_rest/all.mk.in
@@ -0,0 +1,14 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c rest.c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
+
+
+
+
diff --git a/src/modules/rlm_rest/config.h.in b/src/modules/rlm_rest/config.h.in
new file mode 100644
index 0000000..b46972a
--- /dev/null
+++ b/src/modules/rlm_rest/config.h.in
@@ -0,0 +1,85 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Build with JSON support from json-c */
+#undef HAVE_JSON
+
+/* json.h is at json-c/json.h relative to include dir */
+#undef HAVE_JSONMC_JSON_H
+
+/* Define to 1 if you have the `json_c_version' function. */
+#undef HAVE_JSON_C_VERSION
+
+/* json.h is at json/json.h relative to include dir */
+#undef HAVE_JSON_JSON_H
+
+/* Define to 1 if you have the `json_type_to_name' function. */
+#undef HAVE_JSON_TYPE_TO_NAME
+
+/* Define to 1 if you have a functional curl library. */
+#undef HAVE_LIBCURL
+
+/* Defined if libcurl supports AsynchDNS */
+#undef LIBCURL_FEATURE_ASYNCHDNS
+
+/* Defined if libcurl supports IDN */
+#undef LIBCURL_FEATURE_IDN
+
+/* Defined if libcurl supports IPv6 */
+#undef LIBCURL_FEATURE_IPV6
+
+/* Defined if libcurl supports KRB4 */
+#undef LIBCURL_FEATURE_KRB4
+
+/* Defined if libcurl supports libz */
+#undef LIBCURL_FEATURE_LIBZ
+
+/* Defined if libcurl supports NTLM */
+#undef LIBCURL_FEATURE_NTLM
+
+/* Defined if libcurl supports SSL */
+#undef LIBCURL_FEATURE_SSL
+
+/* Defined if libcurl supports SSPI */
+#undef LIBCURL_FEATURE_SSPI
+
+/* Defined if libcurl supports DICT */
+#undef LIBCURL_PROTOCOL_DICT
+
+/* Defined if libcurl supports FILE */
+#undef LIBCURL_PROTOCOL_FILE
+
+/* Defined if libcurl supports FTP */
+#undef LIBCURL_PROTOCOL_FTP
+
+/* Defined if libcurl supports FTPS */
+#undef LIBCURL_PROTOCOL_FTPS
+
+/* Defined if libcurl supports HTTP */
+#undef LIBCURL_PROTOCOL_HTTP
+
+/* Defined if libcurl supports HTTPS */
+#undef LIBCURL_PROTOCOL_HTTPS
+
+/* Defined if libcurl supports IMAP */
+#undef LIBCURL_PROTOCOL_IMAP
+
+/* Defined if libcurl supports LDAP */
+#undef LIBCURL_PROTOCOL_LDAP
+
+/* Defined if libcurl supports POP3 */
+#undef LIBCURL_PROTOCOL_POP3
+
+/* Defined if libcurl supports RTSP */
+#undef LIBCURL_PROTOCOL_RTSP
+
+/* Defined if libcurl supports SMTP */
+#undef LIBCURL_PROTOCOL_SMTP
+
+/* Defined if libcurl supports TELNET */
+#undef LIBCURL_PROTOCOL_TELNET
+
+/* Defined if libcurl supports TFTP */
+#undef LIBCURL_PROTOCOL_TFTP
+
+/* Define curl_free() as free() if our version of curl lacks curl_free. */
+#undef curl_free
diff --git a/src/modules/rlm_rest/configure b/src/modules/rlm_rest/configure
new file mode 100755
index 0000000..206d190
--- /dev/null
+++ b/src/modules/rlm_rest/configure
@@ -0,0 +1,5255 @@
+#! /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_rest.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+targetname
+mod_ldflags
+mod_cflags
+LIBCURL
+LIBCURL_CPPFLAGS
+_libcurl_config
+AWK
+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_rest
+with_libcurl
+with_jsonc_include_dir
+with_jsonc_lib_dir
+with_jsonc_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_rest build without rlm_rest
+ --with-libcurl=PREFIX look for the curl library in PREFIX/lib and headers
+ in PREFIX/include
+ --with-jsonc-include-dir=DIR
+ Directory where the json-c includes may be found
+ --with-jsonc-lib-dir=DIR
+ Directory where the json-c libraries may be found
+ --with-jsonc-dir=DIR Base directory where json-c is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+# Check whether --with-rlm_rest was given.
+if test "${with_rlm_rest+set}" = set; then :
+ withval=$with_rlm_rest;
+fi
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+if test x$with_rlm_rest != xno; then
+
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-libcurl was given.
+if test "${with_libcurl+set}" = set; then :
+ withval=$with_libcurl; _libcurl_with=$withval
+else
+ _libcurl_with=yes
+fi
+
+
+ if test "$_libcurl_with" != "no" ; then
+
+ for ac_prog in gawk mawk nawk awk
+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_AWK+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # 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_AWK="$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
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+
+ _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[1]+256*A[2]+A[3]; print X;}'"
+
+ _libcurl_try_link=yes
+
+ if test -d "$_libcurl_with" ; then
+ LIBCURL_CPPFLAGS="-I$withval/include"
+ _libcurl_ldflags="-L$withval/lib"
+ # Extract the first word of "curl-config", so it can be a program name with args.
+set dummy curl-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path__libcurl_config+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $_libcurl_config in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path__libcurl_config="$_libcurl_config" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in "$withval/bin"
+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_path__libcurl_config="$as_dir/$ac_word$ac_exec_ext"
+ $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
+
+ ;;
+esac
+fi
+_libcurl_config=$ac_cv_path__libcurl_config
+if test -n "$_libcurl_config"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_libcurl_config" >&5
+$as_echo "$_libcurl_config" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ else
+ # Extract the first word of "curl-config", so it can be a program name with args.
+set dummy curl-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path__libcurl_config+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $_libcurl_config in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path__libcurl_config="$_libcurl_config" # Let the user override the test with a path.
+ ;;
+ *)
+ 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_path__libcurl_config="$as_dir/$ac_word$ac_exec_ext"
+ $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
+
+ ;;
+esac
+fi
+_libcurl_config=$ac_cv_path__libcurl_config
+if test -n "$_libcurl_config"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_libcurl_config" >&5
+$as_echo "$_libcurl_config" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+
+ if test x$_libcurl_config != "x" ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the version of libcurl" >&5
+$as_echo_n "checking for the version of libcurl... " >&6; }
+if ${libcurl_cv_lib_curl_version+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $2}'`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libcurl_cv_lib_curl_version" >&5
+$as_echo "$libcurl_cv_lib_curl_version" >&6; }
+
+ _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse`
+ _libcurl_wanted=`echo 7.19.1 | $_libcurl_version_parse`
+
+ if test $_libcurl_wanted -gt 0 ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcurl >= version 7.19.1" >&5
+$as_echo_n "checking for libcurl >= version 7.19.1... " >&6; }
+if ${libcurl_cv_lib_version_ok+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test $_libcurl_version -ge $_libcurl_wanted ; then
+ libcurl_cv_lib_version_ok=yes
+ else
+ libcurl_cv_lib_version_ok=no
+ fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libcurl_cv_lib_version_ok" >&5
+$as_echo "$libcurl_cv_lib_version_ok" >&6; }
+ fi
+
+ if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then
+ if test x"$LIBCURL_CPPFLAGS" = "x" ; then
+ LIBCURL_CPPFLAGS=`$_libcurl_config --cflags`
+ fi
+ if test x"$LIBCURL" = "x" ; then
+ LIBCURL=`$_libcurl_config --libs`
+
+ # This is so silly, but Apple actually has a bug in their
+ # curl-config script. Fixed in Tiger, but there are still
+ # lots of Panther installs around.
+ case "${host}" in
+ powerpc-apple-darwin7*)
+ LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'`
+ ;;
+ esac
+ fi
+
+ # All curl-config scripts support --feature
+ _libcurl_features=`$_libcurl_config --feature`
+
+ # Is it modern enough to have --protocols? (7.12.4)
+ if test $_libcurl_version -ge 461828 ; then
+ _libcurl_protocols=`$_libcurl_config --protocols`
+ fi
+ else
+ _libcurl_try_link=no
+ fi
+
+ unset _libcurl_wanted
+ fi
+
+ if test $_libcurl_try_link = yes ; then
+
+ # we didn't find curl-config, so let's see if the user-supplied
+ # link line (or failing that, "-lcurl") is enough.
+ LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"}
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libcurl is usable" >&5
+$as_echo_n "checking whether libcurl is usable... " >&6; }
+if ${libcurl_cv_lib_curl_usable+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ _libcurl_save_cppflags=$CPPFLAGS
+ CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS"
+ _libcurl_save_libs=$LIBS
+ LIBS="$LIBCURL $LIBS"
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <curl/curl.h>
+int
+main ()
+{
+
+/* Try and use a few common options to force a failure if we are
+ missing symbols or can't link. */
+int x;
+curl_easy_setopt(NULL,CURLOPT_URL,NULL);
+x=CURL_ERROR_SIZE;
+x=CURLOPT_WRITEFUNCTION;
+x=CURLOPT_FILE;
+x=CURLOPT_ERRORBUFFER;
+x=CURLOPT_STDERR;
+x=CURLOPT_VERBOSE;
+if (x) ;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ libcurl_cv_lib_curl_usable=yes
+else
+ libcurl_cv_lib_curl_usable=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ CPPFLAGS=$_libcurl_save_cppflags
+ LIBS=$_libcurl_save_libs
+ unset _libcurl_save_cppflags
+ unset _libcurl_save_libs
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libcurl_cv_lib_curl_usable" >&5
+$as_echo "$libcurl_cv_lib_curl_usable" >&6; }
+
+ if test $libcurl_cv_lib_curl_usable = yes ; then
+
+ # Does curl_free() exist in this version of libcurl?
+ # If not, fake it with free()
+
+ _libcurl_save_cppflags=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
+ _libcurl_save_libs=$LIBS
+ LIBS="$LIBS $LIBCURL"
+
+ ac_fn_c_check_func "$LINENO" "curl_free" "ac_cv_func_curl_free"
+if test "x$ac_cv_func_curl_free" = xyes; then :
+
+else
+
+$as_echo "#define curl_free free" >>confdefs.h
+
+fi
+
+
+ CPPFLAGS=$_libcurl_save_cppflags
+ LIBS=$_libcurl_save_libs
+ unset _libcurl_save_cppflags
+ unset _libcurl_save_libs
+
+
+$as_echo "#define HAVE_LIBCURL 1" >>confdefs.h
+
+
+
+
+ for _libcurl_feature in $_libcurl_features ; do
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "libcurl_feature_$_libcurl_feature" | $as_tr_cpp` 1
+_ACEOF
+
+ eval `$as_echo "libcurl_feature_$_libcurl_feature" | $as_tr_sh`=yes
+ done
+
+ if test "x$_libcurl_protocols" = "x" ; then
+
+ # We don't have --protocols, so just assume that all
+ # protocols are available
+ _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP"
+
+ if test x$libcurl_feature_SSL = xyes ; then
+ _libcurl_protocols="$_libcurl_protocols HTTPS"
+
+ # FTPS wasn't standards-compliant until version
+ # 7.11.0 (0x070b00 == 461568)
+ if test $_libcurl_version -ge 461568; then
+ _libcurl_protocols="$_libcurl_protocols FTPS"
+ fi
+ fi
+
+ # RTSP, IMAP, POP3 and SMTP were added in
+ # 7.20.0 (0x071400 == 463872)
+ if test $_libcurl_version -ge 463872; then
+ _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP"
+ fi
+ fi
+
+ for _libcurl_protocol in $_libcurl_protocols ; do
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "libcurl_protocol_$_libcurl_protocol" | $as_tr_cpp` 1
+_ACEOF
+
+ eval `$as_echo "libcurl_protocol_$_libcurl_protocol" | $as_tr_sh`=yes
+ done
+ else
+ unset LIBCURL
+ unset LIBCURL_CPPFLAGS
+ fi
+ fi
+
+ unset _libcurl_try_link
+ unset _libcurl_version_parse
+ unset _libcurl_config
+ unset _libcurl_feature
+ unset _libcurl_features
+ unset _libcurl_protocol
+ unset _libcurl_protocols
+ unset _libcurl_version
+ unset _libcurl_ldflags
+ fi
+
+ if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then
+ # This is the IF-NO path
+ :
+ else
+ # This is the IF-YES path
+ :
+ fi
+
+ unset _libcurl_with
+
+
+ if test "x$libcurl_cv_lib_version_ok" != "xyes"; then
+ fail="$fail libcurl >= 7.19.2"
+ elif test "x$libcurl_cv_lib_curl_usable" != "xyes"; then
+ fail="$fail libcurl"
+ else
+ if test x$libcurl_protocol_HTTP != xyes; then
+ fail="$fail libcurl_protocol_http"
+ fi
+
+ if test x$libcurl_protocol_HTTPS != xyes || test x$libcurl_feature_SSL != xyes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently building without HTTPS support. requires: libcurl_protocol_https." >&5
+$as_echo "$as_me: WARNING: silently building without HTTPS support. requires: libcurl_protocol_https." >&2;}
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: curl-config's cflags were \"${LIBCURL_CPPFLAGS}\"" >&5
+$as_echo "$as_me: curl-config's cflags were \"${LIBCURL_CPPFLAGS}\"" >&6;}
+ LIBCURL_CPPFLAGS=$(echo "$LIBCURL_CPPFLAGS" | sed 's/-I */-isystem /g')
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Sanitized cflags are \"$(echo "${LIBCURL_CPPFLAGS}" | sed 's/-I */-isystem /g')\"" >&5
+$as_echo "$as_me: Sanitized cflags are \"$(echo "${LIBCURL_CPPFLAGS}" | sed 's/-I */-isystem /g')\"" >&6;}
+ fi
+ fi
+
+
+ jsonc_include_dir=
+
+# Check whether --with-jsonc-include-dir was given.
+if test "${with_jsonc_include_dir+set}" = set; then :
+ withval=$with_jsonc_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need jsonc-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+ jsonc_lib_dir=
+
+# Check whether --with-jsonc-lib-dir was given.
+if test "${with_jsonc_lib_dir+set}" = set; then :
+ withval=$with_jsonc_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need jsonc-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-jsonc-dir was given.
+if test "${with_jsonc_dir+set}" = set; then :
+ withval=$with_jsonc_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need json-c-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_lib_dir="$withval/lib"
+ jsonc_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+
+
+ have_json="yes"
+ smart_try_dir="$jsonc_include_dir"
+
+
+ac_safe=`echo "json/json.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_dir="/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 json/json.h in $try" >&5
+$as_echo_n "checking for json/json.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <json/json.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/json/json.h" >&5
+$as_echo_n "checking for ${_prefix}/json/json.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <json/json.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-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 json/json.h" >&5
+$as_echo_n "checking for json/json.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <json/json.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include=" "
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for json/json.h in $try" >&5
+$as_echo_n "checking for json/json.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <json/json.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ 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_json_json_h" != "xyes"; then
+
+
+ac_safe=`echo "json-c/json.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 json-c/json.h in $try" >&5
+$as_echo_n "checking for json-c/json.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <json-c/json.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/json-c/json.h" >&5
+$as_echo_n "checking for ${_prefix}/json-c/json.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <json-c/json.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 json-c/json.h" >&5
+$as_echo_n "checking for json-c/json.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <json-c/json.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include=" "
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for json-c/json.h in $try" >&5
+$as_echo_n "checking for json-c/json.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <json-c/json.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+ if test "x$ac_cv_header_jsonmc_json_h" != "xyes"; then
+ have_json="no"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: json-c headers not found. Use --with-jsonc-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: json-c headers not found. Use --with-jsonc-include-dir=<path>." >&2;}
+ fail="$fail json.h"
+ else
+
+$as_echo "#define HAVE_JSONMC_JSON_H 1" >>confdefs.h
+
+ fi
+ else
+
+$as_echo "#define HAVE_JSON_JSON_H 1" >>confdefs.h
+
+ fi
+
+
+ smart_try_dir="$jsonc_lib_dir"
+
+
+sm_lib_safe=`echo "json-c" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "json_c_version" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for json_c_version in -ljson-c in $try" >&5
+$as_echo_n "checking for json_c_version in -ljson-c in $try... " >&6; }
+ LIBS="-ljson-c $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char json_c_version();
+int
+main ()
+{
+json_c_version()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ljson-c"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for json_c_version in -ljson-c" >&5
+$as_echo_n "checking for json_c_version in -ljson-c... " >&6; }
+ LIBS="-ljson-c $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char json_c_version();
+int
+main ()
+{
+json_c_version()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ljson-c"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$old_LIBS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ for try in /usr/local/lib /opt/lib; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for json_c_version in -ljson-c in $try" >&5
+$as_echo_n "checking for json_c_version in -ljson-c in $try... " >&6; }
+ LIBS="-ljson-c $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char json_c_version();
+int
+main ()
+{
+json_c_version()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ljson-c"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
+fi
+
+ if test "x$ac_cv_lib_json_c_json_c_version" != "xyes"
+ then
+
+
+sm_lib_safe=`echo "json" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "json_tokener_new" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for json_tokener_new in -ljson in $try" >&5
+$as_echo_n "checking for json_tokener_new in -ljson in $try... " >&6; }
+ LIBS="-ljson $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char json_tokener_new();
+int
+main ()
+{
+json_tokener_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ljson"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for json_tokener_new in -ljson" >&5
+$as_echo_n "checking for json_tokener_new in -ljson... " >&6; }
+ LIBS="-ljson $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char json_tokener_new();
+int
+main ()
+{
+json_tokener_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ljson"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$old_LIBS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ for try in /usr/local/lib /opt/lib; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for json_tokener_new in -ljson in $try" >&5
+$as_echo_n "checking for json_tokener_new in -ljson in $try... " >&6; }
+ LIBS="-ljson $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char json_tokener_new();
+int
+main ()
+{
+json_tokener_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ljson"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
+fi
+
+ if test "x$ac_cv_lib_json_json_tokener_new" != "xyes"
+ then
+ have_json="no"
+ fi
+ fi
+
+ if test "x$have_json" = "xyes"; then
+ LDFLAGS="$SMART_LIBS"
+
+ for ac_func in \
+ json_c_version \
+ json_type_to_name
+
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+$as_echo "#define HAVE_JSON 1" >>confdefs.h
+
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: json-c libraries not found. Use --with-jsonc-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: json-c libraries not found. Use --with-jsonc-lib-dir=<path>." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently building without JSON support. requires: json-c" >&5
+$as_echo "$as_me: WARNING: silently building without JSON support. requires: json-c" >&2;}
+ fi
+
+ targetname=rlm_rest
+else
+ targetname=
+ echo \*\*\* module rlm_rest is disabled.
+fi
+
+if test x"$fail" != x""; then
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_rest to disable it explicitly." "$LINENO" 5
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_rest." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_rest." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_rest requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_rest requires: $fail." >&2;};
+ targetname=""
+ fi
+fi
+
+mod_ldflags="$LIBCURL $SMART_LIBS"
+mod_cflags="$LIBCURL_CPPFLAGS $SMART_CPPFLAGS"
+
+
+
+
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+ ;;
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
diff --git a/src/modules/rlm_rest/configure.ac b/src/modules/rlm_rest/configure.ac
new file mode 100644
index 0000000..fde100e
--- /dev/null
+++ b/src/modules/rlm_rest/configure.ac
@@ -0,0 +1,173 @@
+AC_PREREQ([2.68])
+AC_INIT(rlm_rest.c)
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_rest])
+AC_CONFIG_HEADER(config.h)
+
+if test x$with_[]modname != xno; then
+
+ AC_PROG_CC
+ AC_PROG_CPP
+
+ dnl put configuration checks here.
+ dnl set $fail to what's missing, on fatal errors.
+ dnl use AC_MSG_WARN() on important messages.
+
+ dnl ############################################################
+ dnl # Check for curl
+ dnl ############################################################
+
+ LIBCURL_CHECK_CONFIG([], [7.19.1])
+
+ if test "x$libcurl_cv_lib_version_ok" != "xyes"; then
+ fail="$fail libcurl >= 7.19.2"
+ elif test "x$libcurl_cv_lib_curl_usable" != "xyes"; then
+ fail="$fail libcurl"
+ else
+ if test x$libcurl_protocol_HTTP != xyes; then
+ fail="$fail libcurl_protocol_http"
+ fi
+
+ if test x$libcurl_protocol_HTTPS != xyes || test x$libcurl_feature_SSL != xyes; then
+ AC_MSG_WARN([silently building without HTTPS support. requires: libcurl_protocol_https.])
+ else
+ AC_MSG_NOTICE([curl-config's cflags were \"${LIBCURL_CPPFLAGS}\"])
+ LIBCURL_CPPFLAGS=$(echo "$LIBCURL_CPPFLAGS" | sed 's/-I[ ]*/-isystem /g')
+ AC_MSG_NOTICE([Sanitized cflags are \"$(echo "${LIBCURL_CPPFLAGS}" | sed 's/-I[ ]*/-isystem /g')\"])
+ fi
+ fi
+
+ dnl ############################################################
+ dnl # Check for json-c
+ dnl ############################################################
+
+ dnl extra argument: --with-jsonc-include-dir=DIR
+ jsonc_include_dir=
+ AC_ARG_WITH(jsonc-include-dir,
+ [AS_HELP_STRING([--with-jsonc-include-dir=DIR],
+ [Directory where the json-c includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need jsonc-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_include_dir="$withval"
+ ;;
+ esac])
+
+ dnl extra argument: --with-jsonc-lib-dir=DIR
+ jsonc_lib_dir=
+ AC_ARG_WITH(jsonc-lib-dir,
+ [AS_HELP_STRING([--with-jsonc-lib-dir=DIR],
+ [Directory where the json-c libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need jsonc-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_lib_dir="$withval"
+ ;;
+ esac])
+
+ dnl extra argument: --with-jsonc-dir=DIR
+ AC_ARG_WITH(jsonc-dir,
+ [AS_HELP_STRING([--with-jsonc-dir=DIR],
+ [Base directory where json-c is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need json-c-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_lib_dir="$withval/lib"
+ jsonc_include_dir="$withval/include"
+ ;;
+ esac])
+
+
+ dnl ############################################################
+ dnl # Check for json-c header files
+ dnl ############################################################
+
+ have_json="yes"
+ smart_try_dir="$jsonc_include_dir"
+ FR_SMART_CHECK_INCLUDE([json/json.h])
+ if test "x$ac_cv_header_json_json_h" != "xyes"; then
+ FR_SMART_CHECK_INCLUDE([json-c/json.h])
+ if test "x$ac_cv_header_jsonmc_json_h" != "xyes"; then
+ have_json="no"
+ AC_MSG_WARN([json-c headers not found. Use --with-jsonc-include-dir=<path>.])
+ fail="$fail json.h"
+ else
+ AC_DEFINE([HAVE_JSONMC_JSON_H],[1],[json.h is at json-c/json.h relative to include dir])
+ fi
+ else
+ AC_DEFINE([HAVE_JSON_JSON_H],[1],[json.h is at json/json.h relative to include dir])
+ fi
+
+ dnl ############################################################
+ dnl # Check for json-c libraries
+ dnl ############################################################
+
+ smart_try_dir="$jsonc_lib_dir"
+ dnl # Use a json-c specific function which is only
+ dnl # available in newer versions.
+ FR_SMART_CHECK_LIB([json-c], [json_c_version])
+ if test "x$ac_cv_lib_json_c_json_c_version" != "xyes"
+ then
+ dnl # Use a function which is included in legacy versions
+ dnl # but which may be available in other json libraries
+ FR_SMART_CHECK_LIB([json], [json_tokener_new])
+ if test "x$ac_cv_lib_json_json_tokener_new" != "xyes"
+ then
+ have_json="no"
+ fi
+ fi
+
+ if test "x$have_json" = "xyes"; then
+ dnl # Ensure we use the library we just found the rest of the checks
+ LDFLAGS="$SMART_LIBS"
+
+ dnl # Add any optional functions here
+ AC_CHECK_FUNCS(\
+ json_c_version \
+ json_type_to_name
+ )
+
+ AC_DEFINE([HAVE_JSON],[1],[Build with JSON support from json-c])
+ else
+ AC_MSG_WARN([json-c libraries not found. Use --with-jsonc-lib-dir=<path>.])
+ AC_MSG_WARN([silently building without JSON support. requires: json-c])
+ fi
+
+ targetname=modname
+else
+ targetname=
+ echo \*\*\* module modname is disabled.
+fi
+
+dnl Don't change this section.
+if test x"$fail" != x""; then
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ AC_MSG_ERROR([set --without-]modname[ to disable it explicitly.])
+ else
+ AC_MSG_WARN([silently not building ]modname[.])
+ AC_MSG_WARN([FAILURE: ]modname[ requires: $fail.]);
+ targetname=""
+ fi
+fi
+
+mod_ldflags="$LIBCURL $SMART_LIBS"
+mod_cflags="$LIBCURL_CPPFLAGS $SMART_CPPFLAGS"
+
+AC_SUBST(mod_cflags)
+AC_SUBST(mod_ldflags)
+
+AC_SUBST(targetname)
+AC_OUTPUT(all.mk)
+
diff --git a/src/modules/rlm_rest/demo.pl b/src/modules/rlm_rest/demo.pl
new file mode 100755
index 0000000..dcb521b
--- /dev/null
+++ b/src/modules/rlm_rest/demo.pl
@@ -0,0 +1,59 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use HTTP::Daemon;
+use HTTP::Status;
+use HTTP::Response;
+
+# Required else we get weird issues ports being bound after the
+# daemon exits.
+my $daemon;
+my $client;
+
+sub close_client {
+ if (defined $client) {
+ $client->shutdown(2);
+ $client->close();
+ }
+}
+
+sub close_daemon {
+ if (defined $daemon) {
+ print "Closing daemon socket\n";
+ $daemon->shutdown(2);
+ $daemon->close();
+ }
+ close_client();
+}
+
+$SIG{'INT'} = \&close_daemon;
+$SIG{'QUIT'} = \&close_daemon;
+$SIG{'PIPE'} = \&close_client;
+
+$daemon = new HTTP::Daemon(ReuseAddr => 1, LocalAddr => '127.0.0.1', LocalPort => 9090);
+if (!defined $daemon) {
+ die "Error opening socket: $!";
+}
+
+print "Please contact me at: ", $daemon->url, "\n";
+while ($client = $daemon->accept) {
+ $client->timeout(1);
+ while (my $r = $client->get_request) {
+ print "Got " . $r->method . " request for " . $r->url->path . "\n";
+ if ((($r->method eq 'POST') or ($r->method eq 'GET')) and $r->url->path eq "/") {
+ my $resp = HTTP::Response->new( '200', 'OK' );
+
+ $resp->header("Content-Type" => "application/json");
+ $resp->content("{\"control:Cleartext-Password\":\"testing123\",\"reply:Reply-Message\":\"Hello from demo.pl\"}");
+
+ $client->send_response($resp);
+ } else {
+ $client->send_error(RC_FORBIDDEN)
+ }
+ }
+
+ close_client();
+ undef($client);
+}
diff --git a/src/modules/rlm_rest/rest.c b/src/modules/rlm_rest/rest.c
new file mode 100644
index 0000000..fcb3fd1
--- /dev/null
+++ b/src/modules/rlm_rest/rest.c
@@ -0,0 +1,2682 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @brief Functions and datatypes for the REST (HTTP) transport.
+ * @file rest.c
+ *
+ * @copyright 2012-2014 Arran Cudbard-Bell <a.cudbard-bell@freeradius.org>
+ */
+
+RCSID("$Id$")
+
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+
+#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/connection.h>
+
+#include "rest.h"
+
+/*
+ * This is a workaround to backward versions.
+ */
+#if defined(HAVE_JSON) && !defined(JSON_C_MINOR_VERSION) /* The versions less then 10, don't declare the 'JSON_C_MINOR_VERSION'*/
+int json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value);
+int json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value) {
+ *value = json_object_object_get(jso, key);
+
+ return (*value != NULL);
+}
+#endif
+
+/** Table of encoder/decoder support.
+ *
+ * Indexes in this table match the http_body_type_t enum, and should be
+ * updated if additional enum values are added.
+ *
+ * @see http_body_type_t
+ */
+const http_body_type_t http_body_type_supported[HTTP_BODY_NUM_ENTRIES] = {
+ HTTP_BODY_UNKNOWN, // HTTP_BODY_UNKNOWN
+ HTTP_BODY_UNSUPPORTED, // HTTP_BODY_UNSUPPORTED
+ HTTP_BODY_UNSUPPORTED, // HTTP_BODY_UNAVAILABLE
+ HTTP_BODY_UNSUPPORTED, // HTTP_BODY_INVALID
+ HTTP_BODY_NONE, // HTTP_BODY_NONE
+ HTTP_BODY_CUSTOM_XLAT, // HTTP_BODY_CUSTOM_XLAT
+ HTTP_BODY_CUSTOM_LITERAL, // HTTP_BODY_CUSTOM_LITERAL
+ HTTP_BODY_POST, // HTTP_BODY_POST
+#ifdef HAVE_JSON
+ HTTP_BODY_JSON, // HTTP_BODY_JSON
+#else
+ HTTP_BODY_UNAVAILABLE,
+#endif
+ HTTP_BODY_UNSUPPORTED, // HTTP_BODY_XML
+ HTTP_BODY_UNSUPPORTED, // HTTP_BODY_YAML
+ HTTP_BODY_INVALID, // HTTP_BODY_HTML
+ HTTP_BODY_PLAIN // HTTP_BODY_PLAIN
+};
+
+/*
+ * Lib CURL doesn't define symbols for unsupported auth methods
+ */
+#ifndef CURLOPT_TLSAUTH_SRP
+# define CURLOPT_TLSAUTH_SRP 0
+#endif
+#ifndef CURLAUTH_BASIC
+# define CURLAUTH_BASIC 0
+#endif
+#ifndef CURLAUTH_DIGEST
+# define CURLAUTH_DIGEST 0
+#endif
+#ifndef CURLAUTH_DIGEST_IE
+# define CURLAUTH_DIGEST_IE 0
+#endif
+#ifndef CURLAUTH_GSSNEGOTIATE
+# define CURLAUTH_GSSNEGOTIATE 0
+#endif
+#ifndef CURLAUTH_NTLM
+# define CURLAUTH_NTLM 0
+#endif
+#ifndef CURLAUTH_NTLM_WB
+# define CURLAUTH_NTLM_WB 0
+#endif
+
+/*
+ * CURL headers do:
+ *
+ * #define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param)
+ */
+DIAG_OPTIONAL
+DIAG_OFF(disabled-macro-expansion)
+#define SET_OPTION(_x, _y)\
+do {\
+ if ((ret = curl_easy_setopt(candle, _x, _y)) != CURLE_OK) {\
+ option = STRINGIFY(_x);\
+ goto error;\
+ }\
+} while (0)
+
+/*
+ * that macro is originally declared in include/curl/curlver.h
+ * We have to use this as curl uses lots of enums
+ */
+#ifndef CURL_AT_LEAST_VERSION
+# define CURL_VERSION_BITS(x, y, z) ((x) << 16 | (y) << 8 | (z))
+# define CURL_AT_LEAST_VERSION(x, y, z) (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z))
+#endif
+
+const unsigned long http_curl_auth[HTTP_AUTH_NUM_ENTRIES] = {
+ 0, // HTTP_AUTH_UNKNOWN
+ 0, // HTTP_AUTH_NONE
+ CURLOPT_TLSAUTH_SRP, // HTTP_AUTH_TLS_SRP
+ CURLAUTH_BASIC, // HTTP_AUTH_BASIC
+ CURLAUTH_DIGEST, // HTTP_AUTH_DIGEST
+ CURLAUTH_DIGEST_IE, // HTTP_AUTH_DIGEST_IE
+ CURLAUTH_GSSNEGOTIATE, // HTTP_AUTH_GSSNEGOTIATE
+ CURLAUTH_NTLM, // HTTP_AUTH_NTLM
+ CURLAUTH_NTLM_WB, // HTTP_AUTH_NTLM_WB
+ CURLAUTH_ANY, // HTTP_AUTH_ANY
+ CURLAUTH_ANYSAFE // HTTP_AUTH_ANY_SAFE
+};
+
+
+/** Conversion table for method config values.
+ *
+ * HTTP verb strings for http_method_t enum values. Used by libcurl in the
+ * status line of the outgoing HTTP header, by rest_response_header for decoding
+ * incoming HTTP responses, and by the configuration parser.
+ *
+ * @note must be kept in sync with http_method_t enum.
+ *
+ * @see http_method_t
+ * @see fr_str2int
+ * @see fr_int2str
+ */
+const FR_NAME_NUMBER http_method_table[] = {
+ { "UNKNOWN", HTTP_METHOD_UNKNOWN },
+ { "GET", HTTP_METHOD_GET },
+ { "POST", HTTP_METHOD_POST },
+ { "PUT", HTTP_METHOD_PUT },
+ { "PATCH", HTTP_METHOD_PATCH },
+ { "DELETE", HTTP_METHOD_DELETE },
+
+ { NULL , -1 }
+};
+
+/** Conversion table for type config values.
+ *
+ * Textual names for http_body_type_t enum values, used by the
+ * configuration parser.
+ *
+ * @see http_body_Type_t
+ * @see fr_str2int
+ * @see fr_int2str
+ */
+const FR_NAME_NUMBER http_body_type_table[] = {
+ { "unknown", HTTP_BODY_UNKNOWN },
+ { "unsupported", HTTP_BODY_UNSUPPORTED },
+ { "unavailable", HTTP_BODY_UNAVAILABLE },
+ { "invalid", HTTP_BODY_INVALID },
+ { "none", HTTP_BODY_NONE },
+ { "post", HTTP_BODY_POST },
+ { "json", HTTP_BODY_JSON },
+ { "xml", HTTP_BODY_XML },
+ { "yaml", HTTP_BODY_YAML },
+ { "html", HTTP_BODY_HTML },
+ { "plain", HTTP_BODY_PLAIN },
+
+ { NULL , -1 }
+};
+
+const FR_NAME_NUMBER http_auth_table[] = {
+ { "none", HTTP_AUTH_NONE },
+ { "srp", HTTP_AUTH_TLS_SRP },
+ { "basic", HTTP_AUTH_BASIC },
+ { "digest", HTTP_AUTH_DIGEST },
+ { "digest-ie", HTTP_AUTH_DIGEST_IE },
+ { "gss-negotiate", HTTP_AUTH_GSSNEGOTIATE },
+ { "ntlm", HTTP_AUTH_NTLM },
+ { "ntlm-winbind", HTTP_AUTH_NTLM_WB },
+ { "any", HTTP_AUTH_ANY },
+ { "safe", HTTP_AUTH_ANY_SAFE },
+
+ { NULL , -1 }
+};
+
+/** Conversion table for "Content-Type" header values.
+ *
+ * Used by rest_response_header for parsing incoming headers.
+ *
+ * Values we expect to see in the 'Content-Type:' header of the incoming
+ * response.
+ *
+ * Some data types (like YAML) do no have standard MIME types defined,
+ * so multiple types, are listed here.
+ *
+ * @see http_body_Type_t
+ * @see fr_str2int
+ * @see fr_int2str
+ */
+const FR_NAME_NUMBER http_content_type_table[] = {
+ { "application/x-www-form-urlencoded", HTTP_BODY_POST },
+ { "application/json", HTTP_BODY_JSON },
+ { "text/html", HTTP_BODY_HTML },
+ { "text/plain", HTTP_BODY_PLAIN },
+ { "text/xml", HTTP_BODY_XML },
+ { "text/yaml", HTTP_BODY_YAML },
+ { "text/x-yaml", HTTP_BODY_YAML },
+ { "application/yaml", HTTP_BODY_YAML },
+ { "application/x-yaml", HTTP_BODY_YAML },
+
+ { NULL , -1 }
+};
+
+/** Conversion table for "HTTP" protocol version to use.
+ *
+ * Used by rlm_rest_t for specify the http client version.
+ *
+ * Values we expect to use in curl_easy_setopt()
+ *
+ * @see fr_str2int
+ * @see fr_int2str
+ */
+const FR_NAME_NUMBER http_negotiation_table[] = {
+
+ { "1.0", CURL_HTTP_VERSION_1_0 }, //!< Enforce HTTP 1.0 requests.
+ { "1.1", CURL_HTTP_VERSION_1_1 }, //!< Enforce HTTP 1.1 requests.
+/*
+ * These are all enum values
+ */
+#if CURL_AT_LEAST_VERSION(7,49,0)
+ { "2.0", CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE }, //!< Enforce HTTP 2.0 requests.
+#endif
+#if CURL_AT_LEAST_VERSION(7,33,0)
+ { "2.0+auto", CURL_HTTP_VERSION_2_0 }, //!< Attempt HTTP 2 requests. libcurl will fall back
+ ///< to HTTP 1.1 if HTTP 2 can't be negotiated with the
+ ///< server. (Added in 7.33.0)
+#endif
+#if CURL_AT_LEAST_VERSION(7,47,0)
+ { "2.0+tls", CURL_HTTP_VERSION_2TLS }, //!< Attempt HTTP 2 over TLS (HTTPS) only.
+ ///< libcurl will fall back to HTTP 1.1 if HTTP 2
+ ///< can't be negotiated with the HTTPS server.
+ ///< For clear text HTTP servers, libcurl will use 1.1.
+#endif
+ { "default", CURL_HTTP_VERSION_NONE } //!< We don't care about what version the library uses.
+ ///< libcurl will use whatever it thinks fit.
+};
+
+/*
+ * Encoder specific structures.
+ * @todo split encoders/decoders into submodules.
+ */
+typedef struct rest_custom_data {
+ char const *p; //!< how much text we've sent so far.
+} rest_custom_data_t;
+
+#ifdef HAVE_JSON
+/** Flags to control the conversion of JSON values to VALUE_PAIRs.
+ *
+ * These fields are set when parsing the expanded format for value pairs in
+ * JSON, and control how json_pair_make_leaf and json_pair_make convert the JSON
+ * value, and move the new VALUE_PAIR into an attribute list.
+ *
+ * @see json_pair_make
+ * @see json_pair_make_leaf
+ */
+typedef struct json_flags {
+ int do_xlat; //!< If true value will be expanded with xlat.
+ int is_json; //!< If true value will be inserted as raw JSON
+ // (multiple values not supported).
+ FR_TOKEN op; //!< The operator that determines how the new VP
+ // is processed. @see fr_tokens_table
+
+ int8_t tag; //!< Tag to assign to VP.
+} json_flags_t;
+#endif
+
+/** Initialises libcurl.
+ *
+ * Allocates global variables and memory required for libcurl to function.
+ * MUST only be called once per module instance.
+ *
+ * rest_cleanup must not be called if rest_init fails.
+ *
+ * @see rest_cleanup
+ *
+ * @param[in] instance configuration data.
+ * @return 0 if init succeeded -1 if it failed.
+ */
+int rest_init(rlm_rest_t *instance)
+{
+ static bool version_done;
+ CURLcode ret;
+
+ /* developer sanity */
+ rad_assert((sizeof(http_body_type_supported) / sizeof(*http_body_type_supported)) == HTTP_BODY_NUM_ENTRIES);
+
+ ret = curl_global_init(CURL_GLOBAL_ALL);
+ if (ret != CURLE_OK) {
+ ERROR("rlm_rest (%s): CURL init returned error: %i - %s",
+ instance->xlat_name,
+ ret, curl_easy_strerror(ret));
+
+ curl_global_cleanup();
+ return -1;
+ }
+
+ if (!version_done) {
+ curl_version_info_data *curlversion;
+
+ version_done = true;
+
+ curlversion = curl_version_info(CURLVERSION_NOW);
+ if (strcmp(LIBCURL_VERSION, curlversion->version) != 0) {
+ WARN("rlm_rest: libcurl version changed since the server was built");
+ WARN("rlm_rest: linked: %s built: %s", curlversion->version, LIBCURL_VERSION);
+ }
+
+ INFO("rlm_rest: libcurl version: %s", curl_version());
+ }
+
+ return 0;
+}
+
+/** Cleans up after libcurl.
+ *
+ * Wrapper around curl_global_cleanup, frees any memory allocated by rest_init.
+ * Must only be called once per call of rest_init.
+ *
+ * @see rest_init
+ */
+void rest_cleanup(void)
+{
+ curl_global_cleanup();
+}
+
+
+/** Frees a libcurl handle, and any additional memory used by context data.
+ *
+ * @param[in] randle rlm_rest_handle_t to close and free.
+ * @return returns true.
+ */
+static int _mod_conn_free(rlm_rest_handle_t *randle)
+{
+ curl_easy_cleanup(randle->handle);
+
+ return 0;
+}
+
+/** Creates a new connection handle for use by the FR connection API.
+ *
+ * Matches the fr_connection_create_t function prototype, is passed to
+ * fr_connection_pool_init, and called when a new connection is required by the
+ * connection pool API.
+ *
+ * Creates an instances of rlm_rest_handle_t, and rlm_rest_curl_context_t
+ * which hold the context data required for generating requests and parsing
+ * responses.
+ *
+ * If instance->connect_uri is not NULL libcurl will attempt to open a
+ * TCP socket to the server specified in the URI. This is done so that when the
+ * socket is first used, there will already be a cached TCP connection to the
+ * REST server associated with the curl handle.
+ *
+ * @see fr_connection_pool_init
+ * @see fr_connection_create_t
+ * @see connection.c
+ */
+void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
+{
+ rlm_rest_t *inst = instance;
+
+ rlm_rest_handle_t *randle = NULL;
+ rlm_rest_curl_context_t *curl_ctx = NULL;
+
+ CURL *candle = curl_easy_init();
+
+ CURLcode ret = CURLE_OK;
+ char const *option = "unknown";
+
+ if (!candle) {
+ ERROR("rlm_rest (%s): Failed to create CURL handle", inst->xlat_name);
+ return NULL;
+ }
+
+ SET_OPTION(CURLOPT_CONNECTTIMEOUT_MS, inst->connect_timeout);
+
+ if (inst->connect_uri) {
+ /*
+ * re-establish TCP connection to webserver. This would usually be
+ * done on the first request, but we do it here to minimise
+ * latency.
+ */
+ SET_OPTION(CURLOPT_SSL_VERIFYPEER, 0);
+ SET_OPTION(CURLOPT_SSL_VERIFYHOST, 0);
+ SET_OPTION(CURLOPT_CONNECT_ONLY, 1);
+ SET_OPTION(CURLOPT_URL, inst->connect_uri);
+ SET_OPTION(CURLOPT_NOSIGNAL, 1);
+
+ DEBUG("rlm_rest (%s): Connecting to \"%s\"", inst->xlat_name, inst->connect_uri);
+
+ ret = curl_easy_perform(candle);
+ if (ret != CURLE_OK) {
+ ERROR("rlm_rest (%s): Connection failed: %i - %s", inst->xlat_name, ret, curl_easy_strerror(ret));
+
+ goto connection_error;
+ }
+ } else {
+ DEBUG2("rlm_rest (%s): Skipping pre-connect, connect_uri not specified", inst->xlat_name);
+ }
+
+ /*
+ * Allocate memory for the connection handle abstraction.
+ */
+ randle = talloc_zero(ctx, rlm_rest_handle_t);
+ curl_ctx = talloc_zero(randle, rlm_rest_curl_context_t);
+
+ curl_ctx->headers = NULL; /* CURL needs this to be NULL */
+ curl_ctx->request.instance = inst;
+
+ randle->ctx = curl_ctx;
+ randle->handle = candle;
+ talloc_set_destructor(randle, _mod_conn_free);
+
+ /*
+ * Clear any previously configured options for the first request.
+ */
+ curl_easy_reset(candle);
+
+ return randle;
+
+ /*
+ * Cleanup for error conditions.
+ */
+error:
+ ERROR("rlm_rest (%s): Failed setting curl option %s: %s (%i)", inst->xlat_name, option,
+ curl_easy_strerror(ret), ret);
+
+ /*
+ * So we don't leak CURL handles.
+ */
+connection_error:
+ curl_easy_cleanup(candle);
+ if (randle) talloc_free(randle);
+
+ return NULL;
+}
+
+/** Verifies that the last TCP socket associated with a handle is still active.
+ *
+ * Quieries libcurl to try and determine if the TCP socket associated with a
+ * connection handle is still viable.
+ *
+ * @param[in] instance configuration data.
+ * @param[in] handle to check.
+ * @returns false if the last socket is dead, or if the socket state couldn't be
+ * determined, else true.
+ */
+int mod_conn_alive(void *instance, void *handle)
+{
+ rlm_rest_t *inst = instance;
+ rlm_rest_handle_t *randle = handle;
+ CURL *candle = randle->handle;
+
+ long last_socket;
+ CURLcode ret;
+
+ ret = curl_easy_getinfo(candle, CURLINFO_LASTSOCKET, &last_socket);
+ if (ret != CURLE_OK) {
+ ERROR("rlm_rest (%s): Couldn't determine socket state: %i - %s", inst->xlat_name, ret,
+ curl_easy_strerror(ret));
+
+ return false;
+ }
+
+ if (last_socket == -1) {
+ return false;
+ }
+
+ return true;
+}
+
+/** Copies a pre-expanded xlat string to the output buffer
+ *
+ * @param[out] out Char buffer to write encoded data to.
+ * @param[in] size Multiply by nmemb to get the length of ptr.
+ * @param[in] nmemb Multiply by size to get the length of ptr.
+ * @param[in] userdata rlm_rest_request_t to keep encoding state between calls.
+ * @return length of data (including NULL) written to ptr, or 0 if no more
+ * data to write.
+ */
+static size_t rest_encode_custom(void *out, size_t size, size_t nmemb, void *userdata)
+{
+ rlm_rest_request_t *ctx = userdata;
+ rest_custom_data_t *data = ctx->encoder;
+
+ size_t freespace = (size * nmemb) - 1;
+ size_t len;
+
+ len = strlcpy(out, data->p, freespace);
+ if (is_truncated(len, freespace)) {
+ data->p += (freespace - 1);
+ return freespace - 1;
+ }
+ data->p += len;
+
+ return len;
+}
+
+/** Encodes VALUE_PAIR linked list in POST format
+ *
+ * This is a stream function matching the rest_read_t prototype. Multiple
+ * successive calls will return additional encoded VALUE_PAIRs.
+ * Only complete attribute headers @verbatim '<name>=' @endverbatim and values
+ * will be written to the ptr buffer.
+ *
+ * POST request format is:
+ * @verbatim <attribute0>=<value0>&<attribute1>=<value1>&<attributeN>=<valueN>@endverbatim
+ *
+ * All attributes and values are url encoded. There is currently no support for
+ * nested attributes, or attribute qualifiers.
+ *
+ * Nested attributes may be added in the future using
+ * @verbatim <attribute-outer>:<attribute-inner>@endverbatim
+ * to denotate nesting.
+ *
+ * Requires libcurl for url encoding.
+ *
+ * @see rest_decode_post
+ *
+ * @param[out] out Char buffer to write encoded data to.
+ * @param[in] size Multiply by nmemb to get the length of ptr.
+ * @param[in] nmemb Multiply by size to get the length of ptr.
+ * @param[in] userdata rlm_rest_request_t to keep encoding state between calls.
+ * @return length of data (including NULL) written to ptr, or 0 if no more
+ * data to write.
+ */
+static size_t rest_encode_post(void *out, size_t size, size_t nmemb, void *userdata)
+{
+ rlm_rest_request_t *ctx = userdata;
+ REQUEST *request = ctx->request; /* Used by RDEBUG */
+ VALUE_PAIR *vp;
+
+ char *p = out; /* Position in buffer */
+ char *encoded = p; /* Position in buffer of last fully encoded attribute or value */
+ char *escaped; /* Pointer to current URL escaped data */
+
+ size_t len = 0;
+ size_t freespace = (size * nmemb) - 1;
+
+ /* Allow manual chunking */
+ if ((ctx->chunk) && (ctx->chunk <= freespace)) {
+ freespace = (ctx->chunk - 1);
+ }
+
+ if (ctx->state == READ_STATE_END) return 0;
+
+ /* Post data requires no headers */
+ if (ctx->state == READ_STATE_INIT) ctx->state = READ_STATE_ATTR_BEGIN;
+
+ while (freespace > 0) {
+ vp = fr_cursor_current(&ctx->cursor);
+ if (!vp) {
+ ctx->state = READ_STATE_END;
+
+ break;
+ }
+
+ RDEBUG2("Encoding attribute \"%s\"", vp->da->name);
+
+ if (ctx->state == READ_STATE_ATTR_BEGIN) {
+ escaped = curl_escape(vp->da->name, strlen(vp->da->name));
+ if (!escaped) {
+ REDEBUG("Failed escaping string \"%s\"", vp->da->name);
+ return 0;
+ }
+
+ len = strlen(escaped);
+ if (freespace < (1 + len)) {
+ curl_free(escaped);
+ goto no_space;
+ }
+
+ len = sprintf(p, "%s=", escaped);
+ curl_free(escaped);
+ p += len;
+ freespace -= len;
+
+ /*
+ * We wrote the attribute header, record progress.
+ */
+ encoded = p;
+ ctx->state = READ_STATE_ATTR_CONT;
+ }
+
+ /*
+ * Write out single attribute string.
+ */
+ len = vp_prints_value(p, freespace, vp, 0);
+ if (is_truncated(len, freespace)) goto no_space;
+
+ RINDENT();
+ RDEBUG3("Length : %zd", len);
+ REXDENT();
+ if (len > 0) {
+ escaped = curl_escape(p, len);
+ if (!escaped) {
+ REDEBUG("Failed escaping string \"%s\"", vp->da->name);
+ return 0;
+ }
+ len = strlen(escaped);
+
+ if (freespace < len) {
+ curl_free(escaped);
+ goto no_space;
+ }
+
+ len = strlcpy(p, escaped, len + 1);
+
+ curl_free(escaped);
+
+ RINDENT();
+ RDEBUG3("Value : %s", p);
+ REXDENT();
+
+ p += len;
+ freespace -= len;
+ }
+
+ /*
+ * there are no more attributes, stop
+ */
+ if (!fr_cursor_next_peek(&ctx->cursor)) {
+ ctx->state = READ_STATE_END;
+ break;
+ }
+
+ if (freespace < 1) goto no_space;
+ *p++ = '&';
+ freespace--;
+ /*
+ * Only advance once we have a separator
+ * really we should have an additional
+ * state for encoding the separator,
+ * but, we don't, and v3.0.x is stable
+ * so let's do the easiest fix with the
+ * lowest risk.
+ */
+ fr_cursor_next(&ctx->cursor);
+
+ /*
+ * We wrote one full attribute value pair, record progress.
+ */
+ encoded = p;
+ ctx->state = READ_STATE_ATTR_BEGIN;
+ }
+
+ *p = '\0';
+
+ len = p - (char *)out;
+
+ RDEBUG3("POST Data: %s", (char *)out);
+ RDEBUG3("Returning %zd bytes of POST data", len);
+
+ return len;
+
+ /*
+ * Cleanup for error conditions
+ */
+no_space:
+ *encoded = '\0';
+
+ len = encoded - (char *)out;
+
+ RDEBUG3("POST Data: %s", (char *)out);
+
+ /*
+ * The buffer wasn't big enough to encode a single attribute chunk.
+ */
+ if (len == 0) {
+ REDEBUG("Failed encoding attribute");
+ } else {
+ RDEBUG3("Returning %zd bytes of POST data (buffer full or chunk exceeded)", len);
+ }
+
+ return len;
+}
+
+#ifdef HAVE_JSON
+/** Encodes VALUE_PAIR linked list in JSON format
+ *
+ * This is a stream function matching the rest_read_t prototype. Multiple
+ * successive calls will return additional encoded VALUE_PAIRs.
+ *
+ * Only complete attribute headers
+ * @verbatim "<name>":{"type":"<type>","value":[' @endverbatim
+ * and complete attribute values will be written to ptr.
+ *
+ * If an attribute occurs multiple times in the request the attribute values
+ * will be concatenated into a single value array.
+ *
+ * JSON request format is:
+@verbatim
+{
+ "<attribute0>":{
+ "type":"<type0>",
+ "value":[<value0>,<value1>,<valueN>]
+ },
+ "<attribute1>":{
+ "type":"<type1>",
+ "value":[...]
+ },
+ "<attributeN>":{
+ "type":"<typeN>",
+ "value":[...]
+ },
+}
+@endverbatim
+ *
+ * @param[out] out Char buffer to write encoded data to.
+ * @param[in] size Multiply by nmemb to get the length of ptr.
+ * @param[in] nmemb Multiply by size to get the length of ptr.
+ * @param[in] userdata rlm_rest_request_t to keep encoding state between calls.
+ * @return length of data (including NULL) written to ptr, or 0 if no more
+ * data to write.
+ */
+static size_t rest_encode_json(void *out, size_t size, size_t nmemb, void *userdata)
+{
+ rlm_rest_request_t *ctx = userdata;
+ REQUEST *request = ctx->request; /* Used by RDEBUG */
+ VALUE_PAIR *vp, *next;
+
+ char *p = out; /* Position in buffer */
+ char *encoded = p; /* Position in buffer of last fully encoded attribute or value */
+
+ char const *type;
+
+ size_t len = 0;
+ size_t freespace = (size * nmemb) - 1; /* account for the \0 byte here */
+
+ rad_assert(freespace > 0);
+
+ /* Allow manual chunking */
+ if ((ctx->chunk) && (ctx->chunk <= freespace)) {
+ freespace = (ctx->chunk - 1);
+ }
+
+ if (ctx->state == READ_STATE_END) return 0;
+
+ if (ctx->state == READ_STATE_INIT) {
+ ctx->state = READ_STATE_ATTR_BEGIN;
+
+ if (freespace < 1) goto no_space;
+ *p++ = '{';
+ freespace--;
+ }
+
+ for (;;) {
+ vp = fr_cursor_current(&ctx->cursor);
+
+ /*
+ * We've encoded all the VPs
+ *
+ * The check for READ_STATE_ATTR_BEGIN is needed as we might be in
+ * READ_STATE_ATTR_END, and need to close out the current attribute
+ * array.
+ */
+ if (!vp && (ctx->state == READ_STATE_ATTR_BEGIN)) {
+ if (freespace < 1) goto no_space;
+ *p++ = '}';
+ freespace--;
+
+ ctx->state = READ_STATE_END;
+
+ break;
+ }
+
+ if (ctx->state == READ_STATE_ATTR_BEGIN) {
+ /*
+ * New attribute, write name, type, and beginning of value array.
+ */
+ RDEBUG2("Encoding attribute \"%s\"", vp->da->name);
+
+ type = fr_int2str(dict_attr_types, vp->da->type, "<INVALID>");
+
+ if (ctx->section->attr_num) {
+ len = snprintf(p, freespace + 1, "\"%s\":{\"attr_num\":%d,\"type\":\"%s\",\"value\":[",
+ vp->da->name, vp->da->attr, type);
+ } else {
+ len = snprintf(p, freespace + 1, "\"%s\":{\"type\":\"%s\",\"value\":[", vp->da->name, type);
+ }
+
+ if (len >= freespace) goto no_space;
+ p += len;
+ freespace -= len;
+
+ RINDENT();
+ RDEBUG3("Type : %s", type);
+ REXDENT();
+ /*
+ * We wrote the attribute header, record progress
+ */
+ encoded = p;
+ ctx->state = READ_STATE_ATTR_CONT;
+ }
+
+ if (ctx->state == READ_STATE_ATTR_CONT) {
+ for (;;) {
+ size_t attr_space;
+
+ rad_assert(vp); /* coverity */
+
+ /*
+ * We need at least a single byte to write out the
+ * shortest attribute value.
+ */
+ if (freespace < 1) goto no_space;
+
+ /*
+ * Code below expects length of the buffer, so we
+ * add +1 to freespace.
+ *
+ * If we know we need a comma after the value, we
+ * need to -1 to make sure we have enough room to
+ * write that out.
+ */
+ attr_space = fr_cursor_next_peek(&ctx->cursor) ? freespace - 1 : freespace;
+ len = vp_prints_value_json(p, attr_space + 1, vp, ctx->section->raw_value);
+ if (is_truncated(len, attr_space + 1)) goto no_space;
+
+ /*
+ * Show actual value length minus quotes
+ */
+ RINDENT();
+ RDEBUG3("Length : %zu", (size_t) (*p == '"') ? (len - 2) : len);
+ RDEBUG3("Value : %s", p);
+ REXDENT();
+
+ p += len;
+ freespace -= len;
+ encoded = p;
+
+ /*
+ * Multivalued attribute, we sorted all the attributes earlier, so multiple
+ * instances should occur in a contiguous block.
+ */
+ if ((next = fr_cursor_next(&ctx->cursor)) && (vp->da == next->da)) {
+ rad_assert(freespace >= 1);
+ *p++ = ',';
+ freespace--;
+
+ /*
+ * We wrote one attribute value, record progress.
+ */
+ encoded = p;
+ vp = next;
+ continue;
+ }
+ break;
+ }
+ ctx->state = READ_STATE_ATTR_END;
+ }
+
+ if (ctx->state == READ_STATE_ATTR_END) {
+ next = fr_cursor_current(&ctx->cursor);
+ if (freespace < 2) goto no_space;
+ *p++ = ']';
+ *p++ = '}';
+ freespace -= 2;
+
+ if (next) {
+ if (freespace < 1) goto no_space;
+ *p++ = ',';
+ freespace--;
+ }
+
+ /*
+ * We wrote one full attribute value pair, record progress.
+ */
+ encoded = p;
+ ctx->state = READ_STATE_ATTR_BEGIN;
+ }
+ }
+
+ *p = '\0';
+
+ len = p - (char *)out;
+
+ RDEBUG3("JSON Data: %s", (char *)out);
+ RDEBUG3("Returning %zd bytes of JSON data", len);
+
+ return len;
+
+ /*
+ * Were out of buffer space
+ */
+no_space:
+ *encoded = '\0';
+
+ len = encoded - (char *)out;
+
+ RDEBUG3("JSON Data: %s", (char *)out);
+
+ /*
+ * The buffer wasn't big enough to encode a single attribute chunk.
+ */
+ if (len == 0) {
+ REDEBUG("AVP exceeds buffer length or chunk");
+ } else {
+ RDEBUG2("Returning %zd bytes of JSON data (buffer full or chunk exceeded)", len);
+ }
+
+ return len;
+}
+#endif
+
+/** Emulates successive libcurl calls to an encoding function
+ *
+ * This function is used when the request will be sent to the HTTP server as one
+ * contiguous entity. A buffer of REST_BODY_INIT bytes is allocated and passed
+ * to the stream encoding function.
+ *
+ * If the stream function does not return 0, a new buffer is allocated which is
+ * the size of the previous buffer + REST_BODY_INIT bytes, the data from the
+ * previous buffer is copied, and freed, and another call is made to the stream
+ * function, passing a pointer into the new buffer at the end of the previously
+ * written data.
+ *
+ * This process continues until the stream function signals (by returning 0)
+ * that it has no more data to write.
+ *
+ * @param[out] buffer where the pointer to the alloced buffer should
+ * be written.
+ * @param[in] func Stream function.
+ * @param[in] limit Maximum buffer size to alloc.
+ * @param[in] userdata rlm_rest_request_t to keep encoding state between calls to
+ * stream function.
+ * @return the length of the data written to the buffer (excluding NULL) or -1
+ * if alloc >= limit.
+ */
+static ssize_t rest_request_encode_wrapper(char **buffer, rest_read_t func, size_t limit, void *userdata)
+{
+ char *previous = NULL;
+ char *current = NULL;
+
+ size_t alloc = REST_BODY_INIT; /* Size of buffer to alloc */
+ size_t used = 0; /* Size of data written */
+ size_t len = 0;
+
+ while (alloc <= limit) {
+ current = rad_malloc(alloc);
+
+ if (previous) {
+ strlcpy(current, previous, used + 1);
+ free(previous);
+ }
+
+ len = func(current + used, alloc - used, 1, userdata);
+ used += len;
+ if (!len) {
+ *buffer = current;
+ return used;
+ }
+
+ alloc = alloc * 2;
+ previous = current;
+ };
+
+ free(current);
+
+ return -1;
+}
+
+/** (Re-)Initialises the data in a rlm_rest_request_t.
+ *
+ * Resets the values of a rlm_rest_request_t to their defaults.
+ *
+ * @param[in] request Current request.
+ * @param[in] ctx to initialise.
+ * @param[in] sort If true VALUE_PAIRs will be sorted within the VALUE_PAIR
+ * pointer array.
+ */
+static void rest_request_init(REQUEST *request, rlm_rest_request_t *ctx, bool sort)
+{
+ /*
+ * Setup stream read data
+ */
+ ctx->request = request;
+ ctx->state = READ_STATE_INIT;
+
+ /*
+ * Sorts pairs in place, oh well...
+ */
+ if (sort) {
+ fr_pair_list_sort(&request->packet->vps, fr_pair_cmp_by_da_tag);
+ }
+ fr_cursor_init(&ctx->cursor, &request->packet->vps);
+}
+
+/** Converts plain response into a single VALUE_PAIR
+ *
+ * @param[in] instance configuration data.
+ * @param[in] section configuration data.
+ * @param[in] handle rlm_rest_handle_t to use.
+ * @param[in] request Current request.
+ * @param[in] raw buffer containing POST data.
+ * @param[in] rawlen Length of data in raw buffer.
+ * @return the number of VALUE_PAIRs processed or -1 on unrecoverable error.
+ */
+static int rest_decode_plain(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section,
+ REQUEST *request, UNUSED void *handle, char *raw, size_t rawlen)
+{
+ VALUE_PAIR *vp;
+
+ /*
+ * Empty response?
+ */
+ if (*raw == '\0') return 0;
+
+ /*
+ * Use rawlen to protect against overrun, and to cope with any binary data
+ */
+ vp = pair_make_reply("REST-HTTP-Body", NULL, T_OP_ADD);
+ fr_pair_value_bstrncpy(vp, raw, rawlen);
+
+ RDEBUG2("Adding reply:REST-HTTP-Body += \"%s\"", vp->vp_strvalue);
+
+ return 1;
+}
+
+/** Converts POST response into VALUE_PAIRs and adds them to the request
+ *
+ * Accepts VALUE_PAIRS in the same format as rest_encode_post, but with the
+ * addition of optional attribute list qualifiers as part of the attribute name
+ * string.
+ *
+ * If no qualifiers are specified, will default to the request list.
+ *
+ * POST response format is:
+ * @verbatim [outer.][<list>:]<attribute0>=<value0>&[outer.][<list>:]<attribute1>=<value1>&[outer.][<list>:]<attributeN>=<valueN> @endverbatim
+ *
+ * @see rest_encode_post
+ *
+ * @param[in] instance configuration data.
+ * @param[in] section configuration data.
+ * @param[in] handle rlm_rest_handle_t to use.
+ * @param[in] request Current request.
+ * @param[in] raw buffer containing POST data.
+ * @param[in] rawlen Length of data in raw buffer.
+ * @return the number of VALUE_PAIRs processed or -1 on unrecoverable error.
+ */
+static int rest_decode_post(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section,
+ REQUEST *request, void *handle, char *raw, size_t rawlen)
+{
+ rlm_rest_handle_t *randle = handle;
+ CURL *candle = randle->handle;
+
+ char const *p = raw, *q;
+
+ char const *attribute;
+ char *name = NULL;
+ char *value = NULL;
+
+ char *expanded = NULL;
+
+ DICT_ATTR const *da;
+ VALUE_PAIR *vp;
+
+ pair_lists_t list_name;
+ request_refs_t request_name;
+ REQUEST *reference = request;
+ VALUE_PAIR **vps;
+ TALLOC_CTX *ctx;
+
+ size_t len;
+ int curl_len; /* Length from last curl_easy_unescape call */
+
+ int count = 0;
+ int ret;
+
+ /*
+ * Empty response?
+ */
+ while (isspace(*p)) p++;
+ if (*p == '\0') return 0;
+
+ while (((q = strchr(p, '=')) != NULL) && (count < REST_BODY_MAX_ATTRS)) {
+ reference = request;
+
+ name = curl_easy_unescape(candle, p, (q - p), &curl_len);
+ p = (q + 1);
+
+ RDEBUG2("Parsing attribute \"%s\"", name);
+
+ /*
+ * The attribute pointer is updated to point to the portion of
+ * the string after the list qualifier.
+ */
+ attribute = name;
+ attribute += radius_request_name(&request_name, attribute, REQUEST_CURRENT);
+ if (request_name == REQUEST_UNKNOWN) {
+ RWDEBUG("Invalid request qualifier, skipping");
+
+ curl_free(name);
+
+ continue;
+ }
+
+ if (radius_request(&reference, request_name) < 0) {
+ RWDEBUG("Attribute name refers to outer request but not in a tunnel, skipping");
+
+ curl_free(name);
+
+ continue;
+ }
+
+ attribute += radius_list_name(&list_name, attribute, PAIR_LIST_REPLY);
+ if (list_name == PAIR_LIST_UNKNOWN) {
+ RWDEBUG("Invalid list qualifier, skipping");
+ curl_free(name);
+
+ continue;
+ }
+
+ da = dict_attrbyname(attribute);
+ if (!da) {
+ RWDEBUG("Attribute \"%s\" unknown, skipping", attribute);
+
+ curl_free(name);
+
+ continue;
+ }
+
+ vps = radius_list(reference, list_name);
+ rad_assert(vps);
+
+ RINDENT();
+ RDEBUG3("Type : %s", fr_int2str(dict_attr_types, da->type, "<INVALID>"));
+
+ ctx = radius_list_ctx(reference, list_name);
+
+ q = strchr(p, '&');
+ len = (!q) ? (rawlen - (p - raw)) : (unsigned)(q - p);
+
+ value = curl_easy_unescape(candle, p, len, &curl_len);
+
+ /*
+ * If we found a delimiter we want to skip over it,
+ * if we didn't we do *NOT* want to skip over the end
+ * of the buffer...
+ */
+ p += (!q) ? len : (len + 1);
+
+ RDEBUG3("Length : %i", curl_len);
+ RDEBUG3("Value : \"%s\"", value);
+ REXDENT();
+
+ RDEBUG2("Performing xlat expansion of response value");
+
+ if (radius_axlat(&expanded, request, value, NULL, NULL) < 0) {
+ goto skip;
+ }
+
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) {
+ REDEBUG("Failed creating valuepair");
+ talloc_free(expanded);
+
+ goto error;
+ }
+
+ ret = fr_pair_value_from_str(vp, expanded, -1);
+ TALLOC_FREE(expanded);
+ if (ret < 0) {
+ RWDEBUG("Incompatible value assignment, skipping");
+ talloc_free(vp);
+ goto skip;
+ }
+
+ fr_pair_add(vps, vp);
+
+ count++;
+
+ skip:
+ curl_free(name);
+ curl_free(value);
+
+ continue;
+
+ error:
+ curl_free(name);
+ curl_free(value);
+
+ return count;
+ }
+
+ if (!count) {
+ REDEBUG("Malformed POST data \"%s\"", raw);
+ }
+
+ return count;
+
+}
+
+#ifdef HAVE_JSON
+/** Converts JSON "value" key into VALUE_PAIR.
+ *
+ * If leaf is not in fact a leaf node, but contains JSON data, the data will
+ * written to the attribute in JSON string format.
+ *
+ * @param[in] instance configuration data.
+ * @param[in] section configuration data.
+ * @param[in] ctx to allocate new VALUE_PAIRs in.
+ * @param[in] request Current request.
+ * @param[in] da Attribute to create.
+ * @param[in] flags containing the operator other flags controlling value
+ * expansion.
+ * @param[in] leaf object containing the VALUE_PAIR value.
+ * @return The VALUE_PAIR just created, or NULL on error.
+ */
+static VALUE_PAIR *json_pair_make_leaf(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section,
+ TALLOC_CTX *ctx, REQUEST *request, DICT_ATTR const *da,
+ json_flags_t *flags, json_object *leaf)
+{
+ char const *value, *to_parse;
+ char *expanded = NULL;
+ int ret;
+
+ VALUE_PAIR *vp;
+
+ if (json_object_is_type(leaf, json_type_null)) {
+ RDEBUG3("Got null value for attribute \"%s\", skipping...", da->name);
+
+ return NULL;
+ }
+
+ /*
+ * Should encode any nested JSON structures into JSON strings.
+ *
+ * "I knew you liked JSON so I put JSON in your JSON!"
+ */
+ value = json_object_get_string(leaf);
+ if (!value) {
+ RWDEBUG("Failed getting string value for attribute \"%s\", skipping...", da->name);
+
+ return NULL;
+ }
+
+ RINDENT();
+ RDEBUG3("Type : %s", fr_int2str(dict_attr_types, da->type, "<INVALID>"));
+ RDEBUG3("Length : %zu", strlen(value));
+ RDEBUG3("Value : \"%s\"", value);
+ REXDENT();
+
+ if (flags->do_xlat) {
+ if (radius_axlat(&expanded, request, value, NULL, NULL) < 0) {
+ return NULL;
+ }
+
+ to_parse = expanded;
+ } else {
+ to_parse = value;
+ }
+
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) {
+ RWDEBUG("Failed creating valuepair for attribute \"%s\", skipping...", da->name);
+ talloc_free(expanded);
+
+ return NULL;
+ }
+
+ ret = fr_pair_value_from_str(vp, to_parse, -1);
+ talloc_free(expanded);
+ if (ret < 0) {
+ RWDEBUG("Incompatible value assignment for attribute \"%s\", skipping...", da->name);
+ talloc_free(vp);
+
+ return NULL;
+ }
+
+ vp->op = flags->op;
+ vp->tag = flags->tag;
+
+ return vp;
+}
+
+/** Processes JSON response and converts it into multiple VALUE_PAIRs
+ *
+ * Processes JSON attribute declarations in the format below. Will recurse when
+ * processing nested attributes. When processing nested attributes flags and
+ * operators from previous attributes are not inherited.
+ *
+ * JSON response format is:
+@verbatim
+{
+ "<attribute0>":{
+ "do_xlat":<bool>,
+ "is_json":<bool>,
+ "op":"<operator>",
+ "value":[<value0>,<value1>,<valueN>]
+ },
+ "<attribute1>":{
+ "value":{
+ "<nested-attribute0>":{
+ "op":"<operator>",
+ "value":<value0>
+ }
+ }
+ },
+ "<attribute2>":"<value0>",
+ "<attributeN>":[<value0>,<value1>,<valueN>]
+}
+@endverbatim
+ *
+ * JSON valuepair flags:
+ * - do_xlat (optional) Controls xlat expansion of values. Defaults to true.
+ * - is_json (optional) If true, any nested JSON data will be copied to the
+ * VALUE_PAIR in string form. Defaults to true.
+ * - op (optional) Controls how the attribute is inserted into
+ * the target list. Defaults to ':=' (T_OP_SET).
+ *
+ * If "op" is ':=' or '=', it will be automagically changed to '+=' for the
+ * second and subsequent values in multivalued attributes. This does not work
+ * between multiple attribute declarations.
+ *
+ * @see fr_tokens
+ *
+ * @param[in] instance configuration data.
+ * @param[in] section configuration data.
+ * @param[in] request Current request.
+ * @param[in] object containing root node, or parent node.
+ * @param[in] level Current nesting level.
+ * @param[in] max counter, decremented after each VALUE_PAIR is created,
+ * when 0 no more attributes will be processed.
+ * @return number of attributes created or < 0 on error.
+ */
+static int json_pair_make(rlm_rest_t *instance, rlm_rest_section_t *section,
+ REQUEST *request, json_object *object, UNUSED int level, int max)
+{
+ struct lh_entry *entry;
+ int max_attrs = max;
+
+ if (!json_object_is_type(object, json_type_object)) {
+#ifdef HAVE_JSON_TYPE_TO_NAME
+ REDEBUG("Can't process VP container, expected JSON object"
+ "got \"%s\", skipping...",
+ json_type_to_name(json_object_get_type(object)));
+#else
+ REDEBUG("Can't process VP container, expected JSON object"
+ ", skipping...");
+#endif
+ return -1;
+ }
+
+ /*
+ * Process VP container
+ */
+ for (entry = json_object_get_object(object)->head;
+ entry;
+ entry = entry->next) {
+ int i = 0, elements;
+ struct json_object *value, *element, *tmp;
+ TALLOC_CTX *ctx;
+
+ char const *name = (char const *)entry->k;
+
+ json_flags_t flags = {
+ .op = T_OP_SET,
+ .do_xlat = 1,
+ .is_json = 0
+ };
+
+ vp_tmpl_t dst;
+ REQUEST *current = request;
+ VALUE_PAIR **vps, *vp = NULL;
+
+ memset(&dst, 0, sizeof(dst));
+
+ /* Fix the compiler warnings regarding const... */
+ memcpy(&value, &entry->v, sizeof(value));
+
+ /*
+ * Resolve attribute name to a dictionary entry and pairlist.
+ */
+ RDEBUG2("Parsing attribute \"%s\"", name);
+
+ if (tmpl_from_attr_str(&dst, name, REQUEST_CURRENT, PAIR_LIST_REPLY, false, false) <= 0) {
+ RWDEBUG("Failed parsing attribute: %s, skipping...", fr_strerror());
+ continue;
+ }
+
+ if (radius_request(&current, dst.tmpl_request) < 0) {
+ RWDEBUG("Attribute name refers to outer request but not in a tunnel, skipping...");
+ continue;
+ }
+
+ vps = radius_list(current, dst.tmpl_list);
+ if (!vps) {
+ RWDEBUG("List not valid in this context, skipping...");
+ continue;
+ }
+ ctx = radius_list_ctx(current, dst.tmpl_list);
+
+ /*
+ * Alternative JSON structure which allows operator,
+ * and other flags to be specified.
+ *
+ * "<name>":{
+ * "do_xlat":<bool>,
+ * "is_json":<bool>,
+ * "op":"<op>",
+ * "value":<value>
+ * }
+ *
+ * Where value is a:
+ * - [] Multivalued array
+ * - {} Nested Valuepair
+ * - * Integer or string value
+ */
+ if (json_object_is_type(value, json_type_object)) {
+ /*
+ * Process operator if present.
+ */
+ if (json_object_object_get_ex(value, "op", &tmp)) {
+ flags.op = fr_str2int(fr_tokens, json_object_get_string(tmp), 0);
+ if (!flags.op) {
+ RWDEBUG("Invalid operator value \"%s\", skipping...",
+ json_object_get_string(tmp));
+ continue;
+ }
+ }
+
+ /*
+ * Process optional do_xlat bool.
+ */
+ if (json_object_object_get_ex(value, "do_xlat", &tmp)) {
+ flags.do_xlat = json_object_get_boolean(tmp);
+ }
+
+ /*
+ * Process optional is_json bool.
+ */
+ if (json_object_object_get_ex(value, "is_json", &tmp)) {
+ flags.is_json = json_object_get_boolean(tmp);
+ }
+
+ /*
+ * Value key must be present if were using the expanded syntax.
+ */
+ if (!json_object_object_get_ex(value, "value", &value)) {
+ RWDEBUG("Value key missing, skipping...");
+ continue;
+ }
+ }
+
+ /*
+ * Setup fr_pair_make / recursion loop.
+ */
+ if (!flags.is_json && json_object_is_type(value, json_type_array)) {
+ elements = json_object_array_length(value);
+ if (!elements) {
+ RWDEBUG("Zero length value array, skipping...");
+ continue;
+ }
+ element = json_object_array_get_idx(value, 0);
+ } else {
+ elements = 1;
+ element = value;
+ }
+
+ flags.tag = dst.tmpl_tag;
+
+ /*
+ * A JSON 'value' key, may have multiple elements, iterate
+ * over each of them, creating a new VALUE_PAIR.
+ */
+ do {
+ if (max_attrs-- <= 0) {
+ RWDEBUG("At maximum attribute limit");
+ return max;
+ }
+
+ /*
+ * Automagically switch the op for multivalued attributes.
+ */
+ if (((flags.op == T_OP_SET) || (flags.op == T_OP_EQ)) && (i >= 1)) {
+ flags.op = T_OP_ADD;
+ }
+
+ if (json_object_is_type(element, json_type_object) && !flags.is_json) {
+ /* TODO: Insert nested VP into VP structure...*/
+ RWDEBUG("Found nested VP, these are not yet supported, skipping...");
+
+ continue;
+
+ /*
+ vp = json_pair_make(instance, section,
+ request, value,
+ level + 1, max_attrs);*/
+ } else {
+ vp = json_pair_make_leaf(instance, section, ctx, request,
+ dst.tmpl_da, &flags, element);
+ if (!vp) continue;
+ }
+ rdebug_pair(2, request, vp, NULL);
+ radius_pairmove(current, vps, vp, false);
+ /*
+ * If we call json_object_array_get_idx on something that's not an array
+ * the behaviour appears to be to occasionally segfault.
+ */
+ } while ((++i < elements) && (element = json_object_array_get_idx(value, i)));
+ }
+
+ return max - max_attrs;
+}
+
+/** Converts JSON response into VALUE_PAIRs and adds them to the request.
+ *
+ * Converts the raw JSON string into a json-c object tree and passes it to
+ * json_pair_make. After the tree has been parsed json_object_put is called
+ * which decrements the reference count of the root node by one, and frees
+ * the entire tree.
+ *
+ * @see rest_encode_json
+ * @see json_pair_make
+ *
+ * @param[in] instance configuration data.
+ * @param[in] section configuration data.
+ * @param[in,out] request Current request.
+ * @param[in] handle REST handle.
+ * @param[in] raw buffer containing JSON data.
+ * @param[in] rawlen Length of data in raw buffer.
+ * @return the number of VALUE_PAIRs processed or -1 on unrecoverable error.
+ */
+static int rest_decode_json(rlm_rest_t *instance, rlm_rest_section_t *section,
+ REQUEST *request, UNUSED void *handle, char *raw, UNUSED size_t rawlen)
+{
+ char const *p = raw;
+
+ struct json_object *json;
+
+ int ret;
+
+ /*
+ * Empty response?
+ */
+ while (isspace(*p)) p++;
+ if (*p == '\0') return 0;
+
+ json = json_tokener_parse(p);
+ if (!json) {
+ REDEBUG("Malformed JSON data \"%s\"", raw);
+ return -1;
+ }
+
+ ret = json_pair_make(instance, section, request, json, 0, REST_BODY_MAX_ATTRS);
+
+ /*
+ * Decrement reference count for root object, should free entire JSON tree.
+ */
+ json_object_put(json);
+
+ return ret;
+}
+#endif
+
+/** Processes incoming HTTP header data from libcurl.
+ *
+ * Processes the status line, and Content-Type headers from the incoming HTTP
+ * response.
+ *
+ * Matches prototype for CURLOPT_HEADERFUNCTION, and will be called directly
+ * by libcurl.
+ *
+ * @param[in] in Char buffer where inbound header data is written.
+ * @param[in] size Multiply by nmemb to get the length of ptr.
+ * @param[in] nmemb Multiply by size to get the length of ptr.
+ * @param[in] userdata rlm_rest_response_t to keep parsing state between calls.
+ * @return Length of data processed, or 0 on error.
+ */
+static size_t rest_response_header(void *in, size_t size, size_t nmemb, void *userdata)
+{
+ rlm_rest_response_t *ctx = userdata;
+ REQUEST *request = ctx->request; /* Used by RDEBUG */
+
+ char const *p = in, *q;
+
+ size_t const t = (size * nmemb);
+ size_t s = t;
+ size_t len;
+
+ http_body_type_t type;
+
+ /*
+ * This seems to be curl's indication there are no more header lines.
+ */
+ if (t == 2 && ((p[0] == '\r') && (p[1] == '\n'))) {
+ /*
+ * If we got a 100 Continue, we need to send additional payload data.
+ * reset the state to WRITE_STATE_INIT, so that when were called again
+ * we overwrite previous header data with that from the proper header.
+ */
+ if (ctx->code == 100) {
+ RDEBUG2("Continuing...");
+ ctx->state = WRITE_STATE_INIT;
+ }
+
+ return t;
+ }
+
+ switch (ctx->state) {
+ case WRITE_STATE_INIT:
+ RDEBUG2("Processing response header");
+
+ /*
+ * HTTP/<version> <reason_code>[ <reason_phrase>]\r\n
+ *
+ * "HTTP/1.1 " (8) + "100 " (4) + "\r\n" (2) = 14
+ * "HTTP/2 " (8) + "100 " (4) + "\r\n" (2) = 12
+ */
+ if (s < 12) {
+ REDEBUG("Malformed HTTP header: Status line too short");
+ goto malformed;
+ }
+ /*
+ * Check start of header matches...
+ */
+ if (strncasecmp("HTTP/", p, 5) != 0) {
+ REDEBUG("Malformed HTTP header: Missing HTTP version");
+ goto malformed;
+ }
+ p += 5;
+ s -= 5;
+
+ /*
+ * Skip the version field, next space should mark start of reason_code.
+ */
+ q = memchr(p, ' ', s);
+ if (!q) {
+ RDEBUG("Malformed HTTP header: Missing reason code");
+ goto malformed;
+ }
+
+ s -= (q - p);
+ p = q;
+
+ /*
+ * Process reason_code.
+ *
+ * " 100" (4) + "\r\n" (2) = 6
+ */
+ if (s < 6) {
+ REDEBUG("Malformed HTTP header: Reason code too short");
+ goto malformed;
+ }
+ p++;
+ s--;
+
+ /*
+ * "xxx( |\r)" status code and terminator.
+ */
+ if (!isdigit(p[0]) || !isdigit(p[1]) || !isdigit(p[2]) || !((p[3] == ' ') || (p[3] == '\r'))) goto malformed;
+
+ ctx->code = atoi(p);
+
+ /*
+ * Process reason_phrase (if present).
+ */
+ RINDENT();
+ if (p[3] == ' ') {
+ p += 4;
+ s -= 4;
+
+ q = memchr(p, '\r', s);
+ if (!q) goto malformed;
+
+ len = (q - p);
+
+ RDEBUG2("Status : %i (%.*s)", ctx->code, (int) len, p);
+ } else {
+ RDEBUG2("Status : %i", ctx->code);
+ }
+ REXDENT();
+
+ ctx->state = WRITE_STATE_PARSE_HEADERS;
+
+ break;
+
+ case WRITE_STATE_PARSE_HEADERS:
+ if ((s >= 14) &&
+ (strncasecmp("Content-Type: ", p, 14) == 0)) {
+ p += 14;
+ s -= 14;
+
+ /*
+ * Check to see if there's a parameter separator.
+ */
+ q = memchr(p, ';', s);
+
+ /*
+ * If there's not, find the end of this header.
+ */
+ if (!q) q = memchr(p, '\r', s);
+
+ len = !q ? s : (size_t) (q - p);
+ type = fr_substr2int(http_content_type_table, p, HTTP_BODY_UNKNOWN, len);
+
+ RINDENT();
+ RDEBUG2("Type : %s (%.*s)", fr_int2str(http_body_type_table, type, "<INVALID>"),
+ (int) len, p);
+ REXDENT();
+
+ /*
+ * Assume the force_to value has already been validated.
+ */
+ if (ctx->force_to != HTTP_BODY_UNKNOWN) {
+ if (ctx->force_to != ctx->type) {
+ RDEBUG3("Forcing body type to \"%s\"",
+ fr_int2str(http_body_type_table, ctx->force_to, "<INVALID>"));
+ ctx->type = ctx->force_to;
+ }
+ /*
+ * Figure out if the type is supported by one of the decoders.
+ */
+ } else {
+ ctx->type = http_body_type_supported[type];
+ switch (ctx->type) {
+ case HTTP_BODY_UNKNOWN:
+ RWDEBUG("Couldn't determine type, using the request's type \"%s\".",
+ fr_int2str(http_body_type_table, type, "<INVALID>"));
+ break;
+
+ case HTTP_BODY_UNSUPPORTED:
+ REDEBUG("Type \"%s\" is currently unsupported",
+ fr_int2str(http_body_type_table, type, "<INVALID>"));
+ break;
+
+ case HTTP_BODY_UNAVAILABLE:
+ REDEBUG("Type \"%s\" is unavailable, please rebuild this module with the required "
+ "library", fr_int2str(http_body_type_table, type, "<INVALID>"));
+ break;
+
+ case HTTP_BODY_INVALID:
+ REDEBUG("Type \"%s\" is not a valid web API data markup format",
+ fr_int2str(http_body_type_table, type, "<INVALID>"));
+ break;
+
+ /* supported type */
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return t;
+
+malformed:
+ {
+ char escaped[1024];
+
+ fr_prints(escaped, sizeof(escaped), (char *) in, t, '\0');
+
+ REDEBUG("Received %zu bytes of response data: %s", t, escaped);
+ ctx->code = -1;
+ }
+
+ return (t - s);
+}
+
+/** Processes incoming HTTP body data from libcurl.
+ *
+ * Writes incoming body data to an intermediary buffer for later parsing by
+ * one of the decode functions.
+ *
+ * @param[in] ptr Char buffer where inbound header data is written
+ * @param[in] size Multiply by nmemb to get the length of ptr.
+ * @param[in] nmemb Multiply by size to get the length of ptr.
+ * @param[in] userdata rlm_rest_response_t to keep parsing state between calls.
+ * @return length of data processed, or 0 on error.
+ */
+static size_t rest_response_body(void *ptr, size_t size, size_t nmemb, void *userdata)
+{
+ rlm_rest_response_t *ctx = userdata;
+ REQUEST *request = ctx->request; /* Used by RDEBUG */
+
+ char const *p = ptr, *q;
+ char *tmp;
+
+ size_t const t = (size * nmemb);
+ size_t needed;
+
+ if (t == 0) return 0;
+
+ /*
+ * Any post processing of headers should go here...
+ */
+ if (ctx->state == WRITE_STATE_PARSE_HEADERS) {
+ ctx->state = WRITE_STATE_PARSE_CONTENT;
+ }
+
+ switch (ctx->type) {
+ case HTTP_BODY_UNSUPPORTED:
+ case HTTP_BODY_UNAVAILABLE:
+ case HTTP_BODY_INVALID:
+ while ((q = memchr(p, '\n', t - (p - (char *)ptr)))) {
+ REDEBUG("%.*s", (int) (q - p), p);
+ p = q + 1;
+ }
+
+ if (*p != '\0') {
+ REDEBUG("%.*s", (int)(t - (p - (char *)ptr)), p);
+ }
+
+ return t;
+
+ case HTTP_BODY_NONE:
+ while ((q = memchr(p, '\n', t - (p - (char *)ptr)))) {
+ RDEBUG3("%.*s", (int) (q - p), p);
+ p = q + 1;
+ }
+
+ if (*p != '\0') {
+ RDEBUG3("%.*s", (int)(t - (p - (char *)ptr)), p);
+ }
+
+ return t;
+
+ default:
+ needed = ctx->used + t + 1;
+ if (needed < REST_BODY_INIT) needed = REST_BODY_INIT;
+
+ if (needed > ctx->alloc) {
+ ctx->alloc = needed;
+
+ tmp = ctx->buffer;
+
+ ctx->buffer = rad_malloc(ctx->alloc);
+
+ /* If data has been written previously */
+ if (tmp) {
+ memcpy(ctx->buffer, tmp, ctx->used);
+ free(tmp);
+ }
+ }
+ strlcpy(ctx->buffer + ctx->used, p, t + 1);
+ ctx->used += t; /* don't include the trailing zero */
+
+ break;
+ }
+
+ return t;
+}
+
+/** Print out the response text as error lines
+ *
+ * @param request The Current request.
+ * @param handle rlm_rest_handle_t used to execute the previous request.
+ */
+void rest_response_error(REQUEST *request, rlm_rest_handle_t *handle)
+{
+ char const *p, *q;
+ size_t len;
+
+ len = rest_get_handle_data(&p, handle);
+ if (len == 0) {
+ RERROR("Server returned no data");
+ return;
+ }
+
+ RERROR("Server returned:");
+ while ((q = strchr(p, '\n'))) {
+ RERROR("%.*s", (int) (q - p), p);
+ p = q + 1;
+ }
+ if (*p != '\0') RERROR("%s", p);
+}
+
+/** (Re-)Initialises the data in a rlm_rest_response_t.
+ *
+ * This resets the values of the a rlm_rest_response_t to their defaults.
+ * Must be called between encoding sessions.
+ *
+ * @see rest_response_body
+ * @see rest_response_header
+ *
+ * @param[in] request Current request.
+ * @param[in] ctx data to initialise.
+ * @param[in] type Default http_body_type to use when decoding raw data, may be
+ * overwritten by rest_response_header.
+ */
+static void rest_response_init(REQUEST *request, rlm_rest_response_t *ctx, http_body_type_t type)
+{
+ ctx->request = request;
+ ctx->type = type;
+ ctx->state = WRITE_STATE_INIT;
+ ctx->alloc = 0;
+ ctx->used = 0;
+ ctx->buffer = NULL;
+}
+
+/** Extracts pointer to buffer containing response data
+ *
+ * @param[out] out Where to write the pointer to the buffer.
+ * @param[in] handle used for the last request.
+ * @return > 0 if data is available.
+ */
+size_t rest_get_handle_data(char const **out, rlm_rest_handle_t *handle)
+{
+ rlm_rest_curl_context_t *ctx = handle->ctx;
+
+ rad_assert(ctx->response.buffer || (!ctx->response.buffer && !ctx->response.used));
+
+ *out = ctx->response.buffer;
+ return ctx->response.used;
+}
+
+/** Configures body specific curlopts.
+ *
+ * Configures libcurl handle to use either chunked mode, where the request
+ * data will be sent using multiple HTTP requests, or contiguous mode where
+ * the request data will be sent in a single HTTP request.
+ *
+ * @param[in] instance configuration data.
+ * @param[in] section configuration data.
+ * @param[in] request Current request.
+ * @param[in] handle rlm_rest_handle_t to configure.
+ * @param[in] func to pass to libcurl for chunked.
+ * transfers (NULL if not using chunked mode).
+ * @return 0 on success -1 on error.
+ */
+static int rest_request_config_body(UNUSED rlm_rest_t *instance, rlm_rest_section_t *section,
+ REQUEST *request, rlm_rest_handle_t *handle, rest_read_t func)
+{
+ rlm_rest_curl_context_t *ctx = handle->ctx;
+ CURL *candle = handle->handle;
+
+ CURLcode ret = CURLE_OK;
+ char const *option = "unknown";
+
+ ssize_t len;
+
+ /*
+ * We were provided with no read function, assume this means
+ * no body should be sent.
+ */
+ if (!func) {
+ SET_OPTION(CURLOPT_POSTFIELDSIZE, 0);
+ return 0;
+ }
+
+ /*
+ * Chunked transfer encoding means the body will be sent in
+ * multiple parts.
+ */
+ if (section->chunk > 0) {
+ SET_OPTION(CURLOPT_READDATA, &ctx->request);
+ SET_OPTION(CURLOPT_READFUNCTION, func);
+
+ return 0;
+ }
+
+ /*
+ * If were not doing chunked encoding then we read the entire
+ * body into a buffer, and send it in one go.
+ */
+ len = rest_request_encode_wrapper(&ctx->body, func, REST_BODY_MAX_LEN, &ctx->request);
+ if (len <= 0) {
+ REDEBUG("Failed creating HTTP body content");
+ return -1;
+ }
+
+ SET_OPTION(CURLOPT_POSTFIELDS, ctx->body);
+ SET_OPTION(CURLOPT_POSTFIELDSIZE, len);
+
+ return 0;
+
+error:
+ REDEBUG("Failed setting curl option %s: %s (%i)", option, curl_easy_strerror(ret), ret);
+
+ return -1;
+}
+
+/** Configures request curlopts.
+ *
+ * Configures libcurl handle setting various curlopts for things like local
+ * client time, Content-Type, and other FreeRADIUS custom headers.
+ *
+ * Current FreeRADIUS custom headers are:
+ * - X-FreeRADIUS-Section The module section being processed.
+ * - X-FreeRADIUS-Server The current virtual server the REQUEST is
+ * passing through.
+ *
+ * Sets up callbacks for all response processing (buffers and body data).
+ *
+ * @param[in] instance configuration data.
+ * @param[in] section configuration data.
+ * @param[in] handle to configure.
+ * @param[in] request Current request.
+ * @param[in] method to use (HTTP verbs PUT, POST, DELETE etc...).
+ * @param[in] type Content-Type for request encoding, also sets the default for decoding.
+ * @param[in] username to use for HTTP authentication, may be NULL in which case configured defaults will be used.
+ * @param[in] password to use for HTTP authentication, may be NULL in which case configured defaults will be used.
+ * @param[in] uri buffer containing the expanded URI to send the request to.
+ * @return 0 on success (all opts configured) -1 on error.
+ */
+int rest_request_config(rlm_rest_t *instance, rlm_rest_section_t *section,
+ REQUEST *request, void *handle, http_method_t method,
+ http_body_type_t type,
+ char const *uri, char const *username, char const *password)
+{
+ rlm_rest_handle_t *randle = handle;
+ rlm_rest_curl_context_t *ctx = randle->ctx;
+ CURL *candle = randle->handle;
+
+ http_auth_type_t auth = section->auth;
+
+ CURLcode ret = CURLE_OK;
+ char const *option = "unknown";
+ char const *content_type;
+
+ VALUE_PAIR *header;
+ vp_cursor_t headers;
+
+ char buffer[512];
+
+ rad_assert(candle);
+ rad_assert((!username && !password) || (username && password));
+
+ buffer[(sizeof(buffer) - 1)] = '\0';
+
+ /*
+ * Setup any header options and generic headers.
+ */
+ SET_OPTION(CURLOPT_URL, uri);
+ SET_OPTION(CURLOPT_NOSIGNAL, 1);
+ SET_OPTION(CURLOPT_USERAGENT, "FreeRADIUS " RADIUSD_VERSION_STRING);
+
+ /*
+ * As described in https://curl.se/libcurl/c/CURLOPT_HTTP_VERSION.html,
+ * The libcurl decides which http version should be
+ * used by default accoring by library version.
+ */
+ if (instance->http_negotiation != CURL_HTTP_VERSION_NONE) {
+ RDEBUG3("Set HTTP negotiation for %s", instance->http_negotiation_str);
+ SET_OPTION(CURLOPT_HTTP_VERSION, instance->http_negotiation);
+ }
+
+ content_type = fr_int2str(http_content_type_table, type, section->body_str);
+ snprintf(buffer, sizeof(buffer), "Content-Type: %s", content_type);
+ ctx->headers = curl_slist_append(ctx->headers, buffer);
+ if (!ctx->headers) goto error_header;
+
+ // Pass configuration to the request
+ ctx->request.section = section;
+
+ SET_OPTION(CURLOPT_CONNECTTIMEOUT_MS, instance->connect_timeout);
+ SET_OPTION(CURLOPT_TIMEOUT_MS, section->timeout);
+
+#ifdef CURLOPT_PROTOCOLS
+ SET_OPTION(CURLOPT_PROTOCOLS, (CURLPROTO_HTTP | CURLPROTO_HTTPS));
+#endif
+
+ /*
+ * FreeRADIUS custom headers
+ */
+ RDEBUG3("Adding custom headers:");
+ RINDENT();
+ snprintf(buffer, sizeof(buffer), "X-FreeRADIUS-Section: %s", section->name);
+ RDEBUG3("%s", buffer);
+ ctx->headers = curl_slist_append(ctx->headers, buffer);
+ if (!ctx->headers) goto error_header;
+
+ snprintf(buffer, sizeof(buffer), "X-FreeRADIUS-Server: %s", request->server);
+ RDEBUG3("%s", buffer);
+ ctx->headers = curl_slist_append(ctx->headers, buffer);
+ if (!ctx->headers) goto error_header;
+
+ fr_cursor_init(&headers, &request->config);
+ while (fr_cursor_next_by_num(&headers, PW_REST_HTTP_HEADER, 0, TAG_ANY)) {
+ header = fr_cursor_remove(&headers);
+ if (!strchr(header->vp_strvalue, ':')) {
+ RWDEBUG("Invalid HTTP header \"%s\" must be in format '<attribute>: <value>'. Skipping...",
+ header->vp_strvalue);
+ talloc_free(header);
+ continue;
+ }
+ RDEBUG3("%s", header->vp_strvalue);
+ ctx->headers = curl_slist_append(ctx->headers, header->vp_strvalue);
+ talloc_free(header);
+ }
+ REXDENT();
+
+ /*
+ * Configure HTTP verb (GET, POST, PUT, PATCH, DELETE, other...)
+ */
+ switch (method) {
+ case HTTP_METHOD_GET:
+ SET_OPTION(CURLOPT_HTTPGET, 1L);
+ break;
+
+ case HTTP_METHOD_POST:
+ SET_OPTION(CURLOPT_POST, 1L);
+ break;
+
+ case HTTP_METHOD_PUT:
+ /*
+ * Do not set CURLOPT_PUT, this will cause libcurl
+ * to ignore CURLOPT_POSTFIELDs and attempt to read
+ * whatever was set with CURLOPT_READDATA, which by
+ * default is stdin.
+ *
+ * This is many cases will cause the server to block,
+ * indefinitely.
+ */
+ SET_OPTION(CURLOPT_CUSTOMREQUEST, "PUT");
+ break;
+
+ case HTTP_METHOD_PATCH:
+ SET_OPTION(CURLOPT_CUSTOMREQUEST, "PATCH");
+ break;
+
+ case HTTP_METHOD_DELETE:
+ SET_OPTION(CURLOPT_CUSTOMREQUEST, "DELETE");
+ break;
+
+ case HTTP_METHOD_CUSTOM:
+ SET_OPTION(CURLOPT_CUSTOMREQUEST, section->method_str);
+ break;
+
+ default:
+ rad_assert(0);
+ break;
+ };
+
+ /*
+ * Set user based authentication parameters
+ */
+ if (auth) {
+ if ((auth >= HTTP_AUTH_BASIC) &&
+ (auth <= HTTP_AUTH_ANY_SAFE)) {
+ SET_OPTION(CURLOPT_HTTPAUTH, http_curl_auth[auth]);
+
+ if (username) {
+ SET_OPTION(CURLOPT_USERNAME, username);
+ } else if (section->username) {
+ if (radius_xlat(buffer, sizeof(buffer), request, section->username, NULL, NULL) < 0) {
+ option = STRINGIFY(CURLOPT_USERNAME);
+ goto error;
+ }
+ SET_OPTION(CURLOPT_USERNAME, buffer);
+ }
+
+ if (password) {
+ SET_OPTION(CURLOPT_PASSWORD, password);
+ } else if (section->password) {
+ if (radius_xlat(buffer, sizeof(buffer), request, section->password, NULL, NULL) < 0) {
+ option = STRINGIFY(CURLOPT_PASSWORD);
+ goto error;
+ }
+ SET_OPTION(CURLOPT_PASSWORD, buffer);
+ }
+#ifdef CURLOPT_TLSAUTH_USERNAME
+ } else if (auth == HTTP_AUTH_TLS_SRP) {
+ SET_OPTION(CURLOPT_TLSAUTH_TYPE, http_curl_auth[auth]);
+
+ if (username) {
+ SET_OPTION(CURLOPT_TLSAUTH_USERNAME, username);
+ } else if (section->username) {
+ if (radius_xlat(buffer, sizeof(buffer), request, section->username, NULL, NULL) < 0) {
+ option = STRINGIFY(CURLOPT_TLSAUTH_USERNAME);
+ goto error;
+ }
+ SET_OPTION(CURLOPT_TLSAUTH_USERNAME, buffer);
+ }
+
+ if (password) {
+ SET_OPTION(CURLOPT_TLSAUTH_PASSWORD, password);
+ } else if (section->password) {
+ if (radius_xlat(buffer, sizeof(buffer), request, section->password, NULL, NULL) < 0) {
+ option = STRINGIFY(CURLOPT_TLSAUTH_PASSWORD);
+ goto error;
+ }
+ SET_OPTION(CURLOPT_TLSAUTH_PASSWORD, buffer);
+ }
+#endif
+ }
+ }
+
+ /*
+ * Set SSL/TLS authentication parameters
+ */
+ if (section->tls_certificate_file) {
+ SET_OPTION(CURLOPT_SSLCERT, section->tls_certificate_file);
+ }
+
+ if (section->tls_private_key_file) {
+ SET_OPTION(CURLOPT_SSLKEY, section->tls_private_key_file);
+ }
+
+ if (section->tls_private_key_password) {
+ SET_OPTION(CURLOPT_KEYPASSWD, section->tls_private_key_password);
+ }
+
+ if (section->tls_ca_file) {
+ SET_OPTION(CURLOPT_ISSUERCERT, section->tls_ca_file);
+ }
+
+ if (section->tls_ca_info_file) {
+ SET_OPTION(CURLOPT_CAINFO, section->tls_ca_info_file);
+ }
+
+ if (section->tls_ca_path) {
+ SET_OPTION(CURLOPT_CAPATH, section->tls_ca_path);
+ }
+
+ if (section->tls_random_file) {
+ SET_OPTION(CURLOPT_RANDOM_FILE, section->tls_random_file);
+ }
+
+ SET_OPTION(CURLOPT_SSL_VERIFYPEER, (section->tls_check_cert == true) ? 1 : 0);
+ SET_OPTION(CURLOPT_SSL_VERIFYHOST, (section->tls_check_cert_cn == true) ? 2 : 0);
+
+ /*
+ * Tell CURL how to get HTTP body content, and how to process incoming data.
+ */
+ rest_response_init(request, &ctx->response, type);
+
+ SET_OPTION(CURLOPT_HEADERFUNCTION, rest_response_header);
+ SET_OPTION(CURLOPT_HEADERDATA, &ctx->response);
+ SET_OPTION(CURLOPT_WRITEFUNCTION, rest_response_body);
+ SET_OPTION(CURLOPT_WRITEDATA, &ctx->response);
+
+ /*
+ * Force parsing the body text as a particular encoding.
+ */
+ ctx->response.force_to = section->force_to;
+
+ switch (method) {
+ case HTTP_METHOD_GET:
+ case HTTP_METHOD_DELETE:
+ RDEBUG3("Using a HTTP method which does not require a body. Forcing request body type to \"none\"");
+ goto finish;
+
+ case HTTP_METHOD_POST:
+ case HTTP_METHOD_PUT:
+ case HTTP_METHOD_PATCH:
+ case HTTP_METHOD_CUSTOM:
+ if (section->chunk > 0) {
+ ctx->request.chunk = section->chunk;
+
+ ctx->headers = curl_slist_append(ctx->headers, "Expect:");
+ if (!ctx->headers) goto error_header;
+
+ ctx->headers = curl_slist_append(ctx->headers, "Transfer-Encoding: chunked");
+ if (!ctx->headers) goto error_header;
+ }
+
+ RDEBUG3("Request body content-type will be \"%s\"",
+ fr_int2str(http_content_type_table, type, section->body_str));
+ break;
+
+ default:
+ rad_assert(0);
+ };
+
+ /*
+ * Setup encoder specific options
+ */
+ switch (type) {
+ case HTTP_BODY_NONE:
+ if (rest_request_config_body(instance, section, request, handle,
+ NULL) < 0) {
+ return -1;
+ }
+
+ break;
+
+ case HTTP_BODY_CUSTOM_XLAT:
+ {
+ rest_custom_data_t *data;
+ char *expanded = NULL;
+
+ if (radius_axlat(&expanded, request, section->data, NULL, NULL) < 0) {
+ return -1;
+ }
+
+ data = talloc_zero(request, rest_custom_data_t);
+ data->p = expanded;
+
+ /* Use the encoder specific pointer to store the data we need to encode */
+ ctx->request.encoder = data;
+ if (rest_request_config_body(instance, section, request, handle,
+ rest_encode_custom) < 0) {
+ TALLOC_FREE(ctx->request.encoder);
+ return -1;
+ }
+
+ break;
+ }
+
+ case HTTP_BODY_CUSTOM_LITERAL:
+ {
+ rest_custom_data_t *data;
+
+ data = talloc_zero(request, rest_custom_data_t);
+ data->p = section->data;
+
+ /* Use the encoder specific pointer to store the data we need to encode */
+ ctx->request.encoder = data;
+ if (rest_request_config_body(instance, section, request, handle,
+ rest_encode_custom) < 0) {
+ TALLOC_FREE(ctx->request.encoder);
+ return -1;
+ }
+ }
+ break;
+
+#ifdef HAVE_JSON
+ case HTTP_BODY_JSON:
+ rest_request_init(request, &ctx->request, true);
+
+ if (rest_request_config_body(instance, section, request, handle,
+ rest_encode_json) < 0) {
+ return -1;
+ }
+
+ break;
+#endif
+
+ case HTTP_BODY_POST:
+ rest_request_init(request, &ctx->request, false);
+
+ if (rest_request_config_body(instance, section, request, handle,
+ rest_encode_post) < 0) {
+ return -1;
+ }
+
+ break;
+
+ default:
+ rad_assert(0);
+ }
+
+
+finish:
+ SET_OPTION(CURLOPT_HTTPHEADER, ctx->headers);
+
+ return 0;
+
+error:
+ REDEBUG("Failed setting curl option %s: %s (%i)", option, curl_easy_strerror(ret), ret);
+ return -1;
+
+error_header:
+ REDEBUG("Failed creating header");
+ REXDENT();
+ return -1;
+}
+
+/** Sends a REST (HTTP) request.
+ *
+ * Send the actual REST request to the server. The response will be handled by
+ * the numerous callbacks configured in rest_request_config.
+ *
+ * @param[in] instance configuration data.
+ * @param[in] section configuration data.
+ * @param[in] request Current request.
+ * @param[in] handle to use.
+ * @return 0 on success or -1 on error.
+ */
+int rest_request_perform(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section,
+ REQUEST *request, void *handle)
+{
+ rlm_rest_handle_t *randle = handle;
+ CURL *candle = randle->handle;
+ CURLcode ret;
+ VALUE_PAIR *vp;
+
+ ret = curl_easy_perform(candle);
+ if (ret != CURLE_OK) {
+ REDEBUG("Request failed: %i - %s", ret, curl_easy_strerror(ret));
+
+ return -1;
+ }
+
+ /*
+ * Save the HTTP return status code.
+ */
+ vp = pair_make_reply("REST-HTTP-Status-Code", NULL, T_OP_SET);
+ vp->vp_integer = rest_get_handle_code(handle);
+
+ RDEBUG2("Adding reply:REST-HTTP-Status-Code = \"%d\"", vp->vp_integer);
+
+ return 0;
+}
+
+/** Sends the response to the correct decode function.
+ *
+ * Uses the Content-Type information written in rest_response_header to
+ * determine the correct decode function to use. The decode function will
+ * then convert the raw received data into VALUE_PAIRs.
+ *
+ * @param[in] instance configuration data.
+ * @param[in] section configuration data.
+ * @param[in] request Current request.
+ * @param[in] handle to use.
+ * @return 0 on success or -1 on error.
+ */
+int rest_response_decode(rlm_rest_t *instance, rlm_rest_section_t *section, REQUEST *request, void *handle)
+{
+ rlm_rest_handle_t *randle = handle;
+ rlm_rest_curl_context_t *ctx = randle->ctx;
+
+ int ret = -1; /* -Wsometimes-uninitialized */
+
+ if (!ctx->response.buffer) {
+ RDEBUG2("Skipping attribute processing, no valid body data received");
+ return 0;
+ }
+
+ switch (ctx->response.type) {
+ case HTTP_BODY_NONE:
+ return 0;
+
+ case HTTP_BODY_PLAIN:
+ ret = rest_decode_plain(instance, section, request, handle, ctx->response.buffer, ctx->response.used);
+ break;
+
+ case HTTP_BODY_POST:
+ ret = rest_decode_post(instance, section, request, handle, ctx->response.buffer, ctx->response.used);
+ break;
+
+#ifdef HAVE_JSON
+ case HTTP_BODY_JSON:
+ ret = rest_decode_json(instance, section, request, handle, ctx->response.buffer, ctx->response.used);
+ break;
+#endif
+
+ case HTTP_BODY_UNSUPPORTED:
+ case HTTP_BODY_UNAVAILABLE:
+ case HTTP_BODY_INVALID:
+ return -1;
+
+ default:
+ rad_assert(0);
+ }
+
+ return ret;
+}
+
+/** Cleans up after a REST request.
+ *
+ * Resets all options associated with a CURL handle, and frees any headers
+ * associated with it.
+ *
+ * Calls rest_read_ctx_free and rest_response_free to free any memory used by
+ * context data.
+ *
+ * @param[in] instance configuration data.
+ * @param[in] section configuration data.
+ * @param[in] handle to cleanup.
+ */
+void rest_request_cleanup(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section, void *handle)
+{
+ rlm_rest_handle_t *randle = handle;
+ rlm_rest_curl_context_t *ctx = randle->ctx;
+ CURL *candle = randle->handle;
+
+ /*
+ * Clear any previously configured options
+ */
+ curl_easy_reset(candle);
+
+ /*
+ * Free header list
+ */
+ if (ctx->headers != NULL) {
+ curl_slist_free_all(ctx->headers);
+ ctx->headers = NULL;
+ }
+
+ /*
+ * Free body data (only used if chunking is disabled)
+ */
+ if (ctx->body != NULL) {
+ free(ctx->body);
+ ctx->body = NULL;
+ }
+
+ /*
+ * Free response data
+ */
+ if (ctx->response.buffer) {
+ free(ctx->response.buffer);
+ ctx->response.buffer = NULL;
+ }
+
+ TALLOC_FREE(ctx->request.encoder);
+ TALLOC_FREE(ctx->response.decoder);
+}
+
+/** URL encodes a string.
+ *
+ * Encode special chars as per RFC 3986 section 4.
+ *
+ * @param[in] request Current request.
+ * @param[out] out Where to write escaped string.
+ * @param[in] outlen Size of out buffer.
+ * @param[in] raw string to be urlencoded.
+ * @param[in] arg pointer, gives context for escaping.
+ * @return length of data written to out (excluding NULL).
+ */
+size_t rest_uri_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *raw, UNUSED void *arg)
+{
+ char *escaped;
+
+ escaped = curl_escape(raw, strlen(raw));
+ strlcpy(out, escaped, outlen);
+ curl_free(escaped);
+
+ return strlen(out);
+}
+
+/** Builds URI; performs XLAT expansions and encoding.
+ *
+ * Splits the URI into "http://example.org" and "/%{xlat}/query/?bar=foo"
+ * Both components are expanded, but values expanded for the second component
+ * are also url encoded.
+ *
+ * @param[out] out Where to write the pointer to the new buffer containing the escaped URI.
+ * @param[in] instance configuration data.
+ * @param[in] uri configuration data.
+ * @param[in] request Current request
+ * @return length of data written to buffer (excluding NULL) or < 0 if an error
+ * occurred.
+ */
+ssize_t rest_uri_build(char **out, UNUSED rlm_rest_t *instance, REQUEST *request, char const *uri)
+{
+ char const *p;
+ char *path_exp = NULL;
+
+ char *scheme;
+ char const *path;
+
+ ssize_t len;
+
+ p = uri;
+
+ /*
+ * All URLs must contain at least <scheme>://<server>/
+ */
+ p = strchr(p, ':');
+ if (!p || (*++p != '/') || (*++p != '/')) {
+ malformed:
+ REDEBUG("Error URI is malformed, can't find start of path");
+ return -1;
+ }
+ p = strchr(p + 1, '/');
+ if (!p) {
+ goto malformed;
+ }
+
+ len = (p - uri);
+
+ /*
+ * Allocate a temporary buffer to hold the first part of the URI
+ */
+ scheme = talloc_array(request, char, len + 1);
+ strlcpy(scheme, uri, len + 1);
+
+ path = (uri + len);
+
+ len = radius_axlat(out, request, scheme, NULL, NULL);
+ talloc_free(scheme);
+ if (len < 0) {
+ TALLOC_FREE(*out);
+
+ return 0;
+ }
+
+ len = radius_axlat(&path_exp, request, path, rest_uri_escape, NULL);
+ if (len < 0) {
+ TALLOC_FREE(*out);
+
+ return 0;
+ }
+
+ MEM(*out = talloc_strdup_append(*out, path_exp));
+ talloc_free(path_exp);
+
+ return talloc_array_length(*out) - 1; /* array_length includes \0 */
+}
+
+/** Unescapes the host portion of a URI string
+ *
+ * This is required because the xlat functions which operate on the input string
+ * cannot distinguish between host and path components.
+ *
+ * @param[out] out Where to write the pointer to the new buffer containing the escaped URI.
+ * @param[in] instance configuration data.
+ * @param[in] request Current request
+ * @param[in] handle to use.
+ * @param[in] uri configuration data.
+ * @return length of data written to buffer (excluding NULL) or < 0 if an error
+ * occurred.
+ */
+ssize_t rest_uri_host_unescape(char **out, UNUSED rlm_rest_t *instance, REQUEST *request,
+ void *handle, char const *uri)
+{
+ rlm_rest_handle_t *randle = handle;
+ CURL *candle = randle->handle;
+
+ char const *p, *q;
+
+ char *scheme;
+
+ ssize_t len;
+
+ p = uri;
+
+ /*
+ * All URLs must contain at least <scheme>://<server>/
+ */
+ p = strchr(p, ':');
+ if (!p || (*++p != '/') || (*++p != '/')) {
+ malformed:
+ REDEBUG("Error URI is malformed, can't find start of path");
+ return -1;
+ }
+ p = strchr(p + 1, '/');
+ if (!p) {
+ goto malformed;
+ }
+
+ len = (p - uri);
+
+ /*
+ * Unescape any special sequences in the first part of the URI
+ */
+ scheme = curl_easy_unescape(candle, uri, len, NULL);
+ if (!scheme) {
+ REDEBUG("Error unescaping host");
+ return -1;
+ }
+
+ /*
+ * URIs can't contain spaces, so anything after the space must
+ * be something else.
+ */
+ q = strchr(p, ' ');
+ *out = q ? talloc_typed_asprintf(request, "%s%.*s", scheme, (int)(q - p), p) :
+ talloc_typed_asprintf(request, "%s%s", scheme, p);
+
+ MEM(*out);
+ curl_free(scheme);
+
+ return talloc_array_length(*out) - 1; /* array_length includes \0 */
+}
diff --git a/src/modules/rlm_rest/rest.h b/src/modules/rlm_rest/rest.h
new file mode 100644
index 0000000..4c41cf4
--- /dev/null
+++ b/src/modules/rlm_rest/rest.h
@@ -0,0 +1,323 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @brief Function prototypes and datatypes for the REST (HTTP) transport.
+ * @file rest.h
+ *
+ * @copyright 2012-2014 Arran Cudbard-Bell <a.cudbard-bell@freeradius.org>
+ */
+
+RCSIDH(other_h, "$Id$")
+
+#include <freeradius-devel/connection.h>
+#include "config.h"
+
+#define CURL_NO_OLDIES 1
+#include <curl/curl.h>
+
+#ifdef HAVE_WDOCUMENTATION
+DIAG_OFF(documentation)
+#endif
+
+#ifdef HAVE_JSON
+# if defined(HAVE_JSONMC_JSON_H)
+# include <json-c/json.h>
+# elif defined(HAVE_JSON_JSON_H)
+# include <json/json.h>
+# endif
+#endif
+
+#ifdef HAVE_WDOCUMENTATION
+DIAG_ON(documentation)
+#endif
+
+#define REST_URI_MAX_LEN 2048
+#define REST_BODY_MAX_LEN 8192
+#define REST_BODY_INIT 1024
+#define REST_BODY_MAX_ATTRS 256
+
+typedef enum {
+ HTTP_METHOD_UNKNOWN = 0,
+ HTTP_METHOD_GET,
+ HTTP_METHOD_POST,
+ HTTP_METHOD_PUT,
+ HTTP_METHOD_PATCH,
+ HTTP_METHOD_DELETE,
+ HTTP_METHOD_CUSTOM //!< Must always come last, should not be in method table
+} http_method_t;
+
+typedef enum {
+ HTTP_BODY_UNKNOWN = 0,
+ HTTP_BODY_UNSUPPORTED,
+ HTTP_BODY_UNAVAILABLE,
+ HTTP_BODY_INVALID,
+ HTTP_BODY_NONE,
+ HTTP_BODY_CUSTOM_XLAT,
+ HTTP_BODY_CUSTOM_LITERAL,
+ HTTP_BODY_POST,
+ HTTP_BODY_JSON,
+ HTTP_BODY_XML,
+ HTTP_BODY_YAML,
+ HTTP_BODY_HTML,
+ HTTP_BODY_PLAIN,
+ HTTP_BODY_NUM_ENTRIES
+} http_body_type_t;
+
+typedef enum {
+ HTTP_AUTH_UNKNOWN = 0,
+ HTTP_AUTH_NONE,
+ HTTP_AUTH_TLS_SRP,
+ HTTP_AUTH_BASIC,
+ HTTP_AUTH_DIGEST,
+ HTTP_AUTH_DIGEST_IE,
+ HTTP_AUTH_GSSNEGOTIATE,
+ HTTP_AUTH_NTLM,
+ HTTP_AUTH_NTLM_WB,
+ HTTP_AUTH_ANY,
+ HTTP_AUTH_ANY_SAFE,
+ HTTP_AUTH_NUM_ENTRIES
+} http_auth_type_t;
+
+/*
+ * Must be updated (in rest.c) if additional values are added to
+ * http_body_type_t
+ */
+extern const http_body_type_t http_body_type_supported[HTTP_BODY_NUM_ENTRIES];
+
+extern const unsigned long http_curl_auth[HTTP_AUTH_NUM_ENTRIES];
+
+extern const FR_NAME_NUMBER http_auth_table[];
+
+extern const FR_NAME_NUMBER http_method_table[];
+
+extern const FR_NAME_NUMBER http_body_type_table[];
+
+extern const FR_NAME_NUMBER http_content_type_table[];
+
+extern const FR_NAME_NUMBER http_negotiation_table[];
+
+/*
+ * Structure for section configuration
+ */
+typedef struct rlm_rest_section_t {
+ char const *name; //!< Section name.
+ char const *uri; //!< URI to send HTTP request to.
+
+ char const *method_str; //!< The string version of the HTTP method.
+ http_method_t method; //!< What HTTP method should be used, GET, POST etc...
+
+ char const *body_str; //!< The string version of the encoding/content type.
+ http_body_type_t body; //!< What encoding type should be used.
+
+ bool attr_num; //!< If true, the the attribute number is supplied for each attribute.
+ bool raw_value; //!< If true, enumerated attributes are provided as a numeric value
+
+ char const *force_to_str; //!< Force decoding with this decoder.
+ http_body_type_t force_to; //!< Override the Content-Type header in the response
+ //!< to force decoding as a particular type.
+
+ char const *data; //!< Custom body data (optional).
+
+ char const *auth_str; //!< The string version of the Auth-Type.
+ http_auth_type_t auth; //!< HTTP auth type.
+ bool require_auth; //!< Whether HTTP-Auth is required or not.
+ char const *username; //!< Username used for HTTP-Auth
+ char const *password; //!< Password used for HTTP-Auth
+
+ char const *tls_certificate_file;
+ char const *tls_private_key_file;
+ char const *tls_private_key_password;
+ char const *tls_ca_file;
+ char const *tls_ca_info_file;
+ char const *tls_ca_path;
+ char const *tls_random_file;
+ bool tls_check_cert;
+ bool tls_check_cert_cn;
+
+ struct timeval timeout_tv; //!< Timeout timeval.
+ long timeout; //!< Timeout in ms.
+ uint32_t chunk; //!< Max chunk-size (mainly for testing the encoders)
+} rlm_rest_section_t;
+
+/*
+ * Structure for module configuration
+ */
+typedef struct rlm_rest_t {
+ char const *xlat_name; //!< Instance name.
+
+ char const *connect_uri; //!< URI we attempt to connect to, to pre-establish
+ //!< TCP connections.
+
+ struct timeval connect_timeout_tv; //!< Connection timeout timeval.
+ long connect_timeout; //!< Connection timeout ms.
+
+ char const *http_negotiation_str; //!< The string version of the http_negotiation
+ long http_negotiation; //!< The HTTP protocol version to use
+
+ fr_connection_pool_t *pool; //!< Pointer to the connection pool.
+
+ rlm_rest_section_t authorize; //!< Configuration specific to authorisation.
+ rlm_rest_section_t authenticate; //!< Configuration specific to authentication.
+ rlm_rest_section_t preacct; //!< Configuration specific to preacct.
+ rlm_rest_section_t accounting; //!< Configuration specific to accounting.
+ rlm_rest_section_t checksimul; //!< Configuration specific to simultaneous session
+ //!< checking.
+ rlm_rest_section_t post_auth; //!< Configuration specific to Post-auth
+
+ rlm_rest_section_t pre_proxy; //!< Configuration specific to pre_proxy
+ rlm_rest_section_t post_proxy; //!< Configuration specific to post_proxy
+
+#ifdef WITH_COA
+ rlm_rest_section_t recv_coa; //!< Configuration specific to recv-coa
+#endif
+} rlm_rest_t;
+
+/*
+ * States for stream based attribute encoders
+ */
+typedef enum {
+ READ_STATE_INIT = 0,
+ READ_STATE_ATTR_BEGIN,
+ READ_STATE_ATTR_CONT,
+ READ_STATE_ATTR_END,
+ READ_STATE_END,
+} read_state_t;
+
+/*
+ * States for the response parser
+ */
+typedef enum {
+ WRITE_STATE_INIT = 0,
+ WRITE_STATE_PARSE_HEADERS,
+ WRITE_STATE_PARSE_CONTENT,
+ WRITE_STATE_DISCARD,
+} write_state_t;
+
+/*
+ * Outbound data context (passed to CURLOPT_READFUNCTION as CURLOPT_READDATA)
+ */
+typedef struct rlm_rest_request_t {
+ rlm_rest_t *instance; //!< This instance of rlm_rest.
+ REQUEST *request; //!< Current request.
+ read_state_t state; //!< Encoder state
+
+ vp_cursor_t cursor; //!< Cursor pointing to the start of the list to encode.
+
+ size_t chunk; //!< Chunk size
+
+ rlm_rest_section_t *section; //!< Configuration data
+
+ void *encoder; //!< Encoder specific data.
+} rlm_rest_request_t;
+
+/*
+ * Curl inbound data context (passed to CURLOPT_WRITEFUNCTION and
+ * CURLOPT_HEADERFUNCTION as CURLOPT_WRITEDATA and CURLOPT_HEADERDATA)
+ */
+typedef struct rlm_rest_response_t {
+ rlm_rest_t *instance; //!< This instance of rlm_rest.
+ REQUEST *request; //!< Current request.
+ write_state_t state; //!< Decoder state.
+
+ char *buffer; //!< Raw incoming HTTP data.
+ size_t alloc; //!< Space allocated for buffer.
+ size_t used; //!< Space used in buffer.
+
+ int code; //!< HTTP Status Code.
+ http_body_type_t type; //!< HTTP Content Type.
+ http_body_type_t force_to; //!< Force decoding the body type as a particular encoding.
+
+ void *decoder; //!< Decoder specific data.
+} rlm_rest_response_t;
+
+/*
+ * Curl context data
+ */
+typedef struct rlm_rest_curl_context_t {
+ struct curl_slist *headers; //!< Any HTTP headers which will be sent with the
+ //!< request.
+
+ char *body; //!< Pointer to the buffer which contains body data/
+ //!< Only used when not performing chunked encoding.
+
+ rlm_rest_request_t request; //!< Request context data.
+ rlm_rest_response_t response; //!< Response context data.
+} rlm_rest_curl_context_t;
+
+/*
+ * Connection API handle
+ */
+typedef struct rlm_rest_handle_t {
+ void *handle; //!< Real Handle.
+ rlm_rest_curl_context_t *ctx; //!< Context.
+} rlm_rest_handle_t;
+
+/*
+ * Function prototype for rest_read_wrapper. Matches CURL's
+ * CURLOPT_READFUNCTION prototype.
+ */
+typedef size_t (*rest_read_t)(void *ptr, size_t size, size_t nmemb,
+ void *userdata);
+
+/*
+ * Connection API callbacks
+ */
+int rest_init(rlm_rest_t *instance);
+
+void rest_cleanup(void);
+
+void *mod_conn_create(TALLOC_CTX *ctx, void *instance);
+
+int mod_conn_alive(void *instance, void *handle);
+
+/*
+ * Request processing API
+ */
+int rest_request_config(rlm_rest_t *instance,
+ rlm_rest_section_t *section, REQUEST *request,
+ void *handle, http_method_t method,
+ http_body_type_t type, char const *uri,
+ char const *username, char const *password) CC_HINT(nonnull (1,2,3,4,7));
+
+int rest_request_perform(rlm_rest_t *instance,
+ rlm_rest_section_t *section, REQUEST *request,
+ void *handle);
+
+int rest_response_decode(rlm_rest_t *instance,
+ UNUSED rlm_rest_section_t *section, REQUEST *request,
+ void *handle);
+
+void rest_response_error(REQUEST *request, rlm_rest_handle_t *handle);
+
+void rest_request_cleanup(rlm_rest_t *instance, rlm_rest_section_t *section,
+ void *handle);
+
+#define rest_get_handle_code(handle)(((rlm_rest_curl_context_t*)((rlm_rest_handle_t*)handle)->ctx)->response.code)
+
+#define rest_get_handle_type(handle)(((rlm_rest_curl_context_t*)((rlm_rest_handle_t*)handle)->ctx)->response.type)
+
+size_t rest_get_handle_data(char const **out, rlm_rest_handle_t *handle);
+
+/*
+ * Helper functions
+ */
+size_t rest_uri_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *raw, UNUSED void *arg);
+ssize_t rest_uri_build(char **out, rlm_rest_t *instance, REQUEST *request, char const *uri);
+ssize_t rest_uri_host_unescape(char **out, UNUSED rlm_rest_t *instance, REQUEST *request,
+ void *handle, char const *uri);
diff --git a/src/modules/rlm_rest/rlm_rest.c b/src/modules/rlm_rest/rlm_rest.c
new file mode 100644
index 0000000..1337ae5
--- /dev/null
+++ b/src/modules/rlm_rest/rlm_rest.c
@@ -0,0 +1,1003 @@
+/*
+ * 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_rest.c
+ * @brief Integrate FreeRADIUS with RESTfull APIs
+ *
+ * @copyright 2012-2014 Arran Cudbard-Bell <arran.cudbardb@freeradius.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/token.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <ctype.h>
+#include "rest.h"
+
+/*
+ * TLS Configuration
+ */
+static CONF_PARSER tls_config[] = {
+ { "ca_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_rest_section_t, tls_ca_file), NULL },
+ { "ca_info_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_rest_section_t, tls_ca_info_file), NULL },
+ { "ca_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_rest_section_t, tls_ca_path), NULL },
+ { "certificate_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_rest_section_t, tls_certificate_file), NULL },
+ { "private_key_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_rest_section_t, tls_private_key_file), NULL },
+ { "private_key_password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, rlm_rest_section_t, tls_private_key_password), NULL },
+ { "random_file", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_section_t, tls_random_file), NULL },
+ { "check_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_rest_section_t, tls_check_cert), "yes" },
+ { "check_cert_cn", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_rest_section_t, tls_check_cert_cn), "yes" },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * A mapping of configuration file names to internal variables.
+ *
+ * Note that the string is dynamically allocated, so it MUST
+ * be freed. When the configuration file parse re-reads the string,
+ * it free's the old one, and strdup's the new one, placing the pointer
+ * to the strdup'd string into 'config.string'. This gets around
+ * buffer over-flows.
+ */
+static const CONF_PARSER section_config[] = {
+ { "uri", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_rest_section_t, uri), "" },
+ { "method", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_section_t, method_str), "GET" },
+ { "body", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_section_t, body_str), "none" },
+ { "attr_num", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_rest_section_t, attr_num), "no" },
+ { "raw_value", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_rest_section_t, raw_value), "no" },
+ { "data", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_rest_section_t, data), NULL },
+ { "force_to", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_section_t, force_to_str), NULL },
+
+ /* User authentication */
+ { "auth", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_section_t, auth_str), "none" },
+ { "username", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_rest_section_t, username), NULL },
+ { "password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_rest_section_t, password), NULL },
+ { "require_auth", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_rest_section_t, require_auth), "no" },
+
+ /* Transfer configuration */
+ { "timeout", FR_CONF_OFFSET(PW_TYPE_TIMEVAL, rlm_rest_section_t, timeout_tv), "4.0" },
+ { "chunk", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_rest_section_t, chunk), "0" },
+
+ /* TLS Parameters */
+ { "tls", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) tls_config },
+ CONF_PARSER_TERMINATOR
+};
+
+static const CONF_PARSER module_config[] = {
+ { "connect_uri", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_t, connect_uri), NULL },
+ { "connect_timeout", FR_CONF_OFFSET(PW_TYPE_TIMEVAL, rlm_rest_t, connect_timeout_tv), "4.0" },
+ { "http_negotiation", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_t, http_negotiation_str), "default" },
+
+ CONF_PARSER_TERMINATOR
+};
+
+static int rlm_rest_perform(rlm_rest_t *instance, rlm_rest_section_t *section, void *handle, REQUEST *request,
+ char const *username, char const *password)
+{
+ ssize_t uri_len;
+ char *uri = NULL;
+
+ int ret;
+
+ RDEBUG("Expanding URI components");
+
+ /*
+ * Build xlat'd URI, this allows REST servers to be specified by
+ * request attributes.
+ */
+ uri_len = rest_uri_build(&uri, instance, request, section->uri);
+ if (uri_len <= 0) return -1;
+
+ RDEBUG("Sending HTTP %s to \"%s\"", fr_int2str(http_method_table, section->method, NULL), uri);
+
+ /*
+ * Configure various CURL options, and initialise the read/write
+ * context data.
+ */
+ ret = rest_request_config(instance, section, request, handle, section->method, section->body,
+ uri, username, password);
+ talloc_free(uri);
+ if (ret < 0) return -1;
+
+ /*
+ * Send the CURL request, pre-parse headers, aggregate incoming
+ * HTTP body data into a single contiguous buffer.
+ */
+ ret = rest_request_perform(instance, section, request, handle);
+ if (ret < 0) return -1;
+
+ return 0;
+}
+
+static void rlm_rest_cleanup(rlm_rest_t *instance, rlm_rest_section_t *section, void *handle)
+{
+ rest_request_cleanup(instance, section, handle);
+}
+
+static ssize_t jsonquote_xlat(UNUSED void *instance, UNUSED REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ char const *p;
+ size_t freespace = outlen;
+ size_t len;
+
+ for (p = fmt; *p != '\0'; p++) {
+ /* Indicate truncation */
+ if (freespace < 3) {
+ *out = '\0';
+ return outlen + 1;
+ }
+
+ if (*p == '"') {
+ *out++ = '\\';
+ *out++ = '"';
+ freespace -= 2;
+ } else if (*p == '\\') {
+ *out++ = '\\';
+ *out++ = '\\';
+ freespace -= 2;
+ } else if (*p == '/') {
+ *out++ = '\\';
+ *out++ = '/';
+ freespace -= 2;
+ } else if (*p >= ' ') {
+ *out++ = *p;
+ freespace--;
+ /*
+ * Unprintable chars
+ */
+ } else {
+ *out++ = '\\';
+ freespace--;
+
+ switch (*p) {
+ case '\b':
+ *out++ = 'b';
+ freespace--;
+ break;
+
+ case '\f':
+ *out++ = 'f';
+ freespace--;
+ break;
+
+ case '\n':
+ *out++ = 'n';
+ freespace--;
+ break;
+
+ case '\r':
+ *out++ = 'r';
+ freespace--;
+ break;
+
+ case '\t':
+ *out++ = 't';
+ freespace--;
+ break;
+
+ default:
+ len = snprintf(out, freespace, "u%04X", (uint8_t) *p);
+ if (is_truncated(len, freespace)) return (outlen - freespace) + len;
+ out += len;
+ freespace -= len;
+ }
+ }
+ }
+
+ *out = '\0';
+
+ return outlen - freespace;
+}
+/*
+ * Simple xlat to read text data from a URL
+ */
+static ssize_t rest_xlat(void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t freespace)
+{
+ rlm_rest_t *inst = instance;
+ void *handle;
+ int hcode;
+ int ret;
+ ssize_t len, outlen = 0;
+ char *uri = NULL;
+ char const *p = fmt, *q;
+ char const *body;
+ http_method_t method;
+
+ /* There are no configurable parameters other than the URI */
+ rlm_rest_section_t section = {
+ .name = "xlat",
+ .method = HTTP_METHOD_GET,
+ .body = HTTP_BODY_NONE,
+ .attr_num = false,
+ .raw_value = false,
+ .body_str = "application/x-www-form-urlencoded",
+ .require_auth = false,
+ .force_to = HTTP_BODY_PLAIN
+ };
+ *out = '\0';
+
+ rad_assert(fmt);
+
+ RDEBUG("Expanding URI components");
+
+ handle = fr_connection_get(inst->pool);
+ if (!handle) return -1;
+
+ /*
+ * Extract the method from the start of the format string (if there is one)
+ */
+ method = fr_substr2int(http_method_table, p, HTTP_METHOD_UNKNOWN, -1);
+ if (method != HTTP_METHOD_UNKNOWN) {
+ section.method = method;
+ p += strlen(http_method_table[method].name);
+ }
+
+ /*
+ * Trim whitespace
+ */
+ while (isspace(*p) && p++);
+
+ /*
+ * Unescape parts of xlat'd URI, this allows REST servers to be specified by
+ * request attributes.
+ */
+ len = rest_uri_host_unescape(&uri, instance, request, handle, p);
+ if (len <= 0) {
+ outlen = -1;
+ goto finish;
+ }
+
+ /*
+ * Extract freeform body data (url can't contain spaces)
+ */
+ q = strchr(p, ' ');
+ if (q && (*++q != '\0')) {
+ section.body = HTTP_BODY_CUSTOM_LITERAL;
+ section.data = q;
+ }
+
+ RDEBUG("Sending HTTP %s to \"%s\"", fr_int2str(http_method_table, section.method, NULL), uri);
+
+ /*
+ * Configure various CURL options, and initialise the read/write
+ * context data.
+ *
+ * @todo We could extract the User-Name and password from the URL string.
+ */
+ ret = rest_request_config(instance, &section, request, handle, section.method, section.body,
+ uri, NULL, NULL);
+ talloc_free(uri);
+ if (ret < 0) {
+ outlen = -1;
+ goto finish;
+ }
+
+ /*
+ * Send the CURL request, pre-parse headers, aggregate incoming
+ * HTTP body data into a single contiguous buffer.
+ */
+ ret = rest_request_perform(instance, &section, request, handle);
+ if (ret < 0) {
+ outlen = -1;
+ goto finish;
+ }
+
+ hcode = rest_get_handle_code(handle);
+ switch (hcode) {
+ case 404:
+ case 410:
+ case 403:
+ case 401:
+ {
+ outlen = -1;
+error:
+ rest_response_error(request, handle);
+ goto finish;
+ }
+ case 204:
+ goto finish;
+
+ default:
+ /*
+ * Attempt to parse content if there was any.
+ */
+ if ((hcode >= 200) && (hcode < 300)) {
+ break;
+ } else if (hcode < 500) {
+ outlen = -2;
+ goto error;
+ } else {
+ outlen = -1;
+ goto error;
+ }
+ }
+
+ len = rest_get_handle_data(&body, handle);
+ if ((size_t) len >= freespace) {
+ REDEBUG("Insufficient space to write HTTP response, needed %zu bytes, have %zu bytes", len + 1,
+ freespace);
+ outlen = -1;
+ goto finish;
+ }
+ if (len > 0) {
+ outlen = len;
+ strlcpy(out, body, len + 1); /* strlcpy takes the size of the buffer */
+ }
+
+finish:
+ rlm_rest_cleanup(instance, &section, handle);
+
+ fr_connection_release(inst->pool, handle);
+
+ return outlen;
+}
+
+/*
+ * Find the named user in this modules database. Create the set
+ * of attribute-value pairs to check and reply with for this user
+ * from the database. The authentication code only needs to check
+ * the password, the rest is done here.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
+{
+ rlm_rest_t *inst = instance;
+ rlm_rest_section_t *section = &inst->authorize;
+
+ void *handle;
+ int hcode;
+ int rcode = RLM_MODULE_OK;
+ int ret;
+
+ if (!section->name) return RLM_MODULE_NOOP;
+
+ handle = fr_connection_get(inst->pool);
+ if (!handle) return RLM_MODULE_FAIL;
+
+ ret = rlm_rest_perform(instance, section, handle, request, NULL, NULL);
+ if (ret < 0) {
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ hcode = rest_get_handle_code(handle);
+ switch (hcode) {
+ case 404:
+ case 410:
+ rcode = RLM_MODULE_NOTFOUND;
+ break;
+
+ case 403:
+ rcode = RLM_MODULE_USERLOCK;
+ break;
+
+ case 401:
+ /*
+ * Attempt to parse content if there was any.
+ */
+ ret = rest_response_decode(inst, section, request, handle);
+ if (ret < 0) {
+ rcode = RLM_MODULE_FAIL;
+ break;
+ }
+
+ rcode = RLM_MODULE_REJECT;
+ break;
+
+ case 204:
+ rcode = RLM_MODULE_OK;
+ break;
+
+ default:
+ /*
+ * Attempt to parse content if there was any.
+ */
+ if ((hcode >= 200) && (hcode < 300)) {
+ ret = rest_response_decode(inst, section, request, handle);
+ if (ret < 0) rcode = RLM_MODULE_FAIL;
+ else if (ret == 0) rcode = RLM_MODULE_OK;
+ else rcode = RLM_MODULE_UPDATED;
+ break;
+ } else if (hcode < 500) {
+ rcode = RLM_MODULE_INVALID;
+ } else {
+ rcode = RLM_MODULE_FAIL;
+ }
+ }
+
+finish:
+ switch (rcode) {
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_USERLOCK:
+ rest_response_error(request, handle);
+ break;
+
+ default:
+ break;
+ }
+
+ rlm_rest_cleanup(instance, section, handle);
+
+ fr_connection_release(inst->pool, handle);
+
+ return rcode;
+}
+
+/*
+ * Authenticate the user with the given password.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
+{
+ rlm_rest_t *inst = instance;
+ rlm_rest_section_t *section = &inst->authenticate;
+
+ void *handle;
+ int hcode;
+ int rcode = RLM_MODULE_OK;
+ int ret;
+
+ VALUE_PAIR const *username;
+ VALUE_PAIR const *password;
+
+ if (!section->name) return RLM_MODULE_NOOP;
+
+ username = request->username;
+ if (!request->username) {
+ REDEBUG("Can't perform authentication, 'User-Name' attribute not found in the request");
+
+ return RLM_MODULE_INVALID;
+ }
+
+ password = request->password;
+ if (!password ||
+ (password->da->attr != PW_USER_PASSWORD)) {
+ REDEBUG("You set 'Auth-Type = REST' for a request that does not contain a User-Password attribute!");
+ return RLM_MODULE_INVALID;
+ }
+
+ handle = fr_connection_get(inst->pool);
+ if (!handle) return RLM_MODULE_FAIL;
+
+ ret = rlm_rest_perform(instance, section, handle, request, username->vp_strvalue, password->vp_strvalue);
+ if (ret < 0) {
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ hcode = rest_get_handle_code(handle);
+ switch (hcode) {
+ case 404:
+ case 410:
+ rcode = RLM_MODULE_NOTFOUND;
+ break;
+
+ case 403:
+ rcode = RLM_MODULE_USERLOCK;
+ break;
+
+ case 401:
+ /*
+ * Attempt to parse content if there was any.
+ */
+ ret = rest_response_decode(inst, section, request, handle);
+ if (ret < 0) {
+ rcode = RLM_MODULE_FAIL;
+ break;
+ }
+
+ rcode = RLM_MODULE_REJECT;
+ break;
+
+ case 204:
+ rcode = RLM_MODULE_OK;
+ break;
+
+ default:
+ /*
+ * Attempt to parse content if there was any.
+ */
+ if ((hcode >= 200) && (hcode < 300)) {
+ ret = rest_response_decode(inst, section, request, handle);
+ if (ret < 0) rcode = RLM_MODULE_FAIL;
+ else if (ret == 0) rcode = RLM_MODULE_OK;
+ else rcode = RLM_MODULE_UPDATED;
+ break;
+ } else if (hcode < 500) {
+ rcode = RLM_MODULE_INVALID;
+ } else {
+ rcode = RLM_MODULE_FAIL;
+ }
+ }
+
+finish:
+ switch (rcode) {
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_USERLOCK:
+ rest_response_error(request, handle);
+ break;
+
+ default:
+ break;
+ }
+
+ rlm_rest_cleanup(instance, section, handle);
+
+ fr_connection_release(inst->pool, handle);
+
+ return rcode;
+}
+
+/*
+ * Do common work.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_common(rlm_rest_t *inst, REQUEST *request, rlm_rest_section_t *section)
+{
+ void *handle;
+ int hcode;
+ int rcode = RLM_MODULE_OK;
+ int ret;
+
+ if (!section->name) return RLM_MODULE_NOOP;
+
+ handle = fr_connection_get(inst->pool);
+ if (!handle) return RLM_MODULE_FAIL;
+
+ ret = rlm_rest_perform(inst, section, handle, request, NULL, NULL);
+ if (ret < 0) {
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ hcode = rest_get_handle_code(handle);
+ if (hcode >= 500) {
+ rcode = RLM_MODULE_FAIL;
+ } else if (hcode == 204) {
+ rcode = RLM_MODULE_OK;
+ } else if ((hcode >= 200) && (hcode < 300)) {
+ ret = rest_response_decode(inst, section, request, handle);
+ if (ret < 0) rcode = RLM_MODULE_FAIL;
+ else if (ret == 0) rcode = RLM_MODULE_OK;
+ else rcode = RLM_MODULE_UPDATED;
+ } else {
+ rcode = RLM_MODULE_INVALID;
+ }
+
+finish:
+ switch (rcode) {
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_FAIL:
+ rest_response_error(request, handle);
+ break;
+
+ default:
+ break;
+ }
+
+ rlm_rest_cleanup(inst, section, handle);
+
+ fr_connection_release(inst->pool, handle);
+
+ return rcode;
+}
+
+
+/*
+ * Send preacct info to a REST API endpoint
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_preacct(void *instance, REQUEST *request)
+{
+ rlm_rest_t *inst = instance;
+ rlm_rest_section_t *section = &inst->preacct;
+
+ return mod_common(inst, request, section);
+}
+/*
+ * Send accounting info to a REST API endpoint
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
+{
+ rlm_rest_t *inst = instance;
+ rlm_rest_section_t *section = &inst->accounting;
+
+ return mod_common(inst, request, section);
+}
+
+/*
+ * Send post-auth info to a REST API endpoint
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
+{
+ rlm_rest_t *inst = instance;
+ rlm_rest_section_t *section = &inst->post_auth;
+
+ return mod_common(inst, request, section);
+}
+
+/*
+ * Send pre-proxy info to a REST API endpoint
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_pre_proxy(void *instance, REQUEST *request)
+{
+ rlm_rest_t *inst = instance;
+ rlm_rest_section_t *section = &inst->pre_proxy;
+
+ return mod_common(inst, request, section);
+}
+
+/*
+ * Send post-proxy info to a REST API endpoint
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_post_proxy(void *instance, REQUEST *request)
+{
+ rlm_rest_t *inst = instance;
+ rlm_rest_section_t *section = &inst->post_proxy;
+
+ return mod_common(inst, request, section);
+}
+
+#ifdef WITH_COA
+/*
+ * Create the set of attribute-value pairs to check and reply
+ * with for this user from the database.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_recv_coa(void *instance, REQUEST *request)
+{
+ rlm_rest_t *inst = instance;
+ rlm_rest_section_t *section = &inst->recv_coa;
+
+ void *handle;
+ int hcode;
+ int rcode = RLM_MODULE_OK;
+ int ret;
+
+ if (!section->name) return RLM_MODULE_NOOP;
+
+ handle = fr_connection_get(inst->pool);
+ if (!handle) return RLM_MODULE_FAIL;
+
+ ret = rlm_rest_perform(instance, section, handle, request, NULL, NULL);
+ if (ret < 0) {
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ hcode = rest_get_handle_code(handle);
+ switch (hcode) {
+ case 404:
+ case 410:
+ rcode = RLM_MODULE_NOTFOUND;
+ break;
+
+ case 403:
+ rcode = RLM_MODULE_USERLOCK;
+ break;
+
+ case 401:
+ /*
+ * Attempt to parse content if there was any.
+ */
+ ret = rest_response_decode(inst, section, request, handle);
+ if (ret < 0) {
+ rcode = RLM_MODULE_FAIL;
+ break;
+ }
+
+ rcode = RLM_MODULE_REJECT;
+ break;
+
+ case 204:
+ rcode = RLM_MODULE_OK;
+ break;
+
+ default:
+ /*
+ * Attempt to parse content if there was any.
+ */
+ if ((hcode >= 200) && (hcode < 300)) {
+ ret = rest_response_decode(inst, section, request, handle);
+ if (ret < 0) rcode = RLM_MODULE_FAIL;
+ else if (ret == 0) rcode = RLM_MODULE_OK;
+ else rcode = RLM_MODULE_UPDATED;
+ break;
+ } else if (hcode < 500) {
+ rcode = RLM_MODULE_INVALID;
+ } else {
+ rcode = RLM_MODULE_FAIL;
+ }
+ }
+
+finish:
+ switch (rcode) {
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_USERLOCK:
+ rest_response_error(request, handle);
+ break;
+
+ default:
+ break;
+ }
+
+ rlm_rest_cleanup(instance, section, handle);
+
+ fr_connection_release(inst->pool, handle);
+
+ return rcode;
+}
+#endif
+
+static int parse_sub_section(CONF_SECTION *parent, rlm_rest_section_t *config, rlm_components_t comp)
+{
+ CONF_SECTION *cs;
+
+ char const *name = section_type_value[comp].section;
+
+ cs = cf_section_sub_find(parent, name);
+ if (!cs) {
+ config->name = NULL;
+ return 0;
+ }
+
+ if (cf_section_parse(cs, config, section_config) < 0) {
+ config->name = NULL;
+ return -1;
+ }
+
+ /*
+ * Add section name (Maybe add to headers later?).
+ */
+ config->name = name;
+
+ /*
+ * Sanity check
+ */
+ if ((config->username && !config->password) || (!config->username && config->password)) {
+ cf_log_err_cs(cs, "'username' and 'password' must both be set or both be absent");
+
+ return -1;
+ }
+
+ /*
+ * Convert HTTP method auth and body type strings into their integer equivalents.
+ */
+ config->auth = fr_str2int(http_auth_table, config->auth_str, HTTP_AUTH_UNKNOWN);
+ if (config->auth == HTTP_AUTH_UNKNOWN) {
+ cf_log_err_cs(cs, "Unknown HTTP auth type '%s'", config->auth_str);
+
+ return -1;
+ } else if ((config->auth != HTTP_AUTH_NONE) && !http_curl_auth[config->auth]) {
+ cf_log_err_cs(cs, "Unsupported HTTP auth type \"%s\", check libcurl version, OpenSSL build "
+ "configuration, then recompile this module", config->auth_str);
+
+ return -1;
+ }
+
+ config->method = fr_str2int(http_method_table, config->method_str, HTTP_METHOD_CUSTOM);
+ config->timeout = ((config->timeout_tv.tv_usec / 1000) + (config->timeout_tv.tv_sec * 1000));
+
+ /*
+ * We don't have any custom user data, so we need to select the right encoder based
+ * on the body type.
+ *
+ * To make this slightly more/less confusing, we accept both canonical body_types,
+ * and content_types.
+ */
+ if (!config->data) {
+ config->body = fr_str2int(http_body_type_table, config->body_str, HTTP_BODY_UNKNOWN);
+ if (config->body == HTTP_BODY_UNKNOWN) {
+ config->body = fr_str2int(http_content_type_table, config->body_str, HTTP_BODY_UNKNOWN);
+ }
+
+ if (config->body == HTTP_BODY_UNKNOWN) {
+ cf_log_err_cs(cs, "Unknown HTTP body type '%s'", config->body_str);
+ return -1;
+ }
+
+ switch (http_body_type_supported[config->body]) {
+ case HTTP_BODY_UNSUPPORTED:
+ cf_log_err_cs(cs, "Unsupported HTTP body type \"%s\", please submit patches",
+ config->body_str);
+ return -1;
+
+ case HTTP_BODY_INVALID:
+ cf_log_err_cs(cs, "Invalid HTTP body type. \"%s\" is not a valid web API data "
+ "markup format", config->body_str);
+ return -1;
+
+ case HTTP_BODY_UNAVAILABLE:
+ cf_log_err_cs(cs, "Unavailable HTTP body type. \"%s\" is not available in this "
+ "build", config->body_str);
+ return -1;
+
+ default:
+ break;
+ }
+ /*
+ * We have custom body data so we set HTTP_BODY_CUSTOM_XLAT, but also need to try and
+ * figure out what content-type to use. So if they've used the canonical form we
+ * need to convert it back into a proper HTTP content_type value.
+ */
+ } else {
+ http_body_type_t body;
+
+ config->body = HTTP_BODY_CUSTOM_XLAT;
+
+ body = fr_str2int(http_body_type_table, config->body_str, HTTP_BODY_UNKNOWN);
+ if (body != HTTP_BODY_UNKNOWN) {
+ config->body_str = fr_int2str(http_content_type_table, body, config->body_str);
+ }
+ }
+
+ if (config->force_to_str) {
+ config->force_to = fr_str2int(http_body_type_table, config->force_to_str, HTTP_BODY_UNKNOWN);
+ if (config->force_to == HTTP_BODY_UNKNOWN) {
+ config->force_to = fr_str2int(http_content_type_table, config->force_to_str, HTTP_BODY_UNKNOWN);
+ }
+
+ if (config->force_to == HTTP_BODY_UNKNOWN) {
+ cf_log_err_cs(cs, "Unknown forced response body type '%s'", config->force_to_str);
+ return -1;
+ }
+
+ switch (http_body_type_supported[config->force_to]) {
+ case HTTP_BODY_UNSUPPORTED:
+ cf_log_err_cs(cs, "Unsupported forced response body type \"%s\", please submit patches",
+ config->force_to_str);
+ return -1;
+
+ case HTTP_BODY_INVALID:
+ cf_log_err_cs(cs, "Invalid HTTP forced response body type. \"%s\" is not a valid web API data "
+ "markup format", config->force_to_str);
+ return -1;
+
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_rest_t *inst = instance;
+
+ inst->xlat_name = cf_section_name2(conf);
+ if (!inst->xlat_name) inst->xlat_name = cf_section_name1(conf);
+
+ /*
+ * Register the rest xlat function
+ */
+ xlat_register(inst->xlat_name, rest_xlat, rest_uri_escape, inst);
+ xlat_register("jsonquote", jsonquote_xlat, NULL, inst);
+
+ return 0;
+}
+
+
+/*
+ * Do any per-module initialization that is separate to each
+ * configured instance of the module. e.g. set up connections
+ * to external databases, read configuration files, set up
+ * dictionary entries, etc.
+ *
+ * If configuration information is given in the config section
+ * that must be referenced in later calls, store a handle to it
+ * in *instance otherwise put a null pointer there.
+ */
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ rlm_rest_t *inst = instance;
+
+ /*
+ * Parse sub-section configs.
+ */
+ if (
+ (parse_sub_section(conf, &inst->authorize, MOD_AUTHORIZE) < 0) ||
+ (parse_sub_section(conf, &inst->authenticate, MOD_AUTHENTICATE) < 0) ||
+ (parse_sub_section(conf, &inst->preacct, MOD_PREACCT) < 0) ||
+ (parse_sub_section(conf, &inst->accounting, MOD_ACCOUNTING) < 0) ||
+ (parse_sub_section(conf, &inst->pre_proxy, MOD_PRE_PROXY) < 0) ||
+ (parse_sub_section(conf, &inst->post_proxy, MOD_POST_PROXY) < 0) ||
+
+#ifdef WITH_COA
+ (parse_sub_section(conf, &inst->recv_coa, MOD_RECV_COA) < 0) ||
+#endif
+
+/* @todo add behaviour for checksimul */
+/* (parse_sub_section(conf, &inst->checksimul, MOD_SESSION) < 0) || */
+ (parse_sub_section(conf, &inst->post_auth, MOD_POST_AUTH) < 0))
+ {
+ return -1;
+ }
+
+ inst->http_negotiation = fr_str2int(http_negotiation_table, inst->http_negotiation_str, -1);
+ if (inst->http_negotiation == -1) {
+ cf_log_err_cs(conf, "Unsupported HTTP version \"%s\".", inst->http_negotiation_str);
+ return -1;
+ }
+
+ /*
+ * Initialise REST libraries.
+ */
+ if (rest_init(inst) < 0) {
+ return -1;
+ }
+
+ inst->connect_timeout = ((inst->connect_timeout_tv.tv_usec / 1000) +
+ (inst->connect_timeout_tv.tv_sec * 1000));
+ inst->pool = fr_connection_pool_module_init(conf, inst, mod_conn_create, mod_conn_alive, NULL);
+ if (!inst->pool) return -1;
+
+ return 0;
+}
+
+/*
+ * Only free memory we allocated. The strings allocated via
+ * cf_section_parse() do not need to be freed.
+ */
+static int mod_detach(void *instance)
+{
+ rlm_rest_t *inst = instance;
+
+ fr_connection_pool_free(inst->pool);
+
+ /* Free any memory used by libcurl */
+ rest_cleanup();
+
+ return 0;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ *
+ * If the module needs to temporarily modify it's instantiation
+ * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
+ * The server will then take care of ensuring that the module
+ * is single-threaded.
+ */
+extern module_t rlm_rest;
+module_t rlm_rest = {
+ .magic = RLM_MODULE_INIT,
+ .name = "rest",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_rest_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_PREACCT] = mod_preacct,
+ [MOD_ACCOUNTING] = mod_accounting,
+ [MOD_POST_AUTH] = mod_post_auth,
+ [MOD_PRE_PROXY] = mod_pre_proxy,
+ [MOD_POST_PROXY] = mod_post_proxy,
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_recv_coa
+#endif
+ },
+};